Support user type annotations in ref
bindings.
This commit adds support for user type annotations in variables declared using `ref` bindings. When a variable declared using a `ref` binding, then the `LocalDecl` has the type `&T` where the `&` was introduced by the `ref` binding but the canonicalized type annotation has only a `T` since the reference is implicit with the `ref` binding. Therefore, to support type annotations, the canonicalized type annotation either needs wrapped in a reference, or the `LocalDecl` type must have a wrapped reference removed for comparison. It is easier to remove the outer reference from the `LocalDecl` for the purpose of comparison, so that is the approach this commit takes.
This commit is contained in:
parent
162dcdc16f
commit
dc41606ff4
7 changed files with 40 additions and 20 deletions
|
@ -307,8 +307,20 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
|
|||
self.sanitize_type(local_decl, local_decl.ty);
|
||||
|
||||
for (user_ty, span) in local_decl.user_ty.projections_and_spans() {
|
||||
let ty = if !local_decl.is_nonref_binding() {
|
||||
// If we have a binding of the form `let ref x: T = ..` then remove the outermost
|
||||
// reference so we can check the type annotation for the remaining type.
|
||||
if let ty::Ref(_, rty, _) = local_decl.ty.sty {
|
||||
rty
|
||||
} else {
|
||||
bug!("{:?} with ref binding has wrong type {}", local, local_decl.ty);
|
||||
}
|
||||
} else {
|
||||
local_decl.ty
|
||||
};
|
||||
|
||||
if let Err(terr) = self.cx.relate_type_and_user_type(
|
||||
local_decl.ty,
|
||||
ty,
|
||||
ty::Variance::Invariant,
|
||||
user_ty,
|
||||
Locations::All(*span),
|
||||
|
|
|
@ -141,6 +141,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
None, remainder_span, lint_level, slice::from_ref(&pattern),
|
||||
ArmHasGuard(false), None);
|
||||
|
||||
debug!("ast_block_stmts: pattern={:?}", pattern);
|
||||
this.visit_bindings(
|
||||
&pattern,
|
||||
&PatternTypeProjections::none(),
|
||||
|
|
|
@ -409,6 +409,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
);
|
||||
let mut scope = self.source_scope;
|
||||
let num_patterns = patterns.len();
|
||||
debug!("declare_bindings: patterns={:?}", patterns);
|
||||
self.visit_bindings(
|
||||
&patterns[0],
|
||||
&PatternTypeProjections::none(),
|
||||
|
@ -499,6 +500,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
&PatternTypeProjections<'tcx>,
|
||||
),
|
||||
) {
|
||||
debug!("visit_bindings: pattern={:?} pattern_user_ty={:?}", pattern, pattern_user_ty);
|
||||
match *pattern.kind {
|
||||
PatternKind::Binding {
|
||||
mutability,
|
||||
|
@ -509,19 +511,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
ref subpattern,
|
||||
..
|
||||
} => {
|
||||
let pattern_ref_binding; // sidestep temp lifetime limitations.
|
||||
let binding_user_ty = match mode {
|
||||
BindingMode::ByValue => { pattern_user_ty }
|
||||
BindingMode::ByRef(..) => {
|
||||
// If this is a `ref` binding (e.g., `let ref
|
||||
// x: T = ..`), then the type of `x` is not
|
||||
// `T` but rather `&T`.
|
||||
pattern_ref_binding = pattern_user_ty.ref_binding();
|
||||
&pattern_ref_binding
|
||||
}
|
||||
};
|
||||
|
||||
f(self, mutability, name, mode, var, pattern.span, ty, binding_user_ty);
|
||||
f(self, mutability, name, mode, var, pattern.span, ty, pattern_user_ty);
|
||||
if let Some(subpattern) = subpattern.as_ref() {
|
||||
self.visit_bindings(subpattern, pattern_user_ty, f);
|
||||
}
|
||||
|
@ -565,6 +555,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
PatternKind::Leaf { ref subpatterns } => {
|
||||
for subpattern in subpatterns {
|
||||
let subpattern_user_ty = pattern_user_ty.leaf(subpattern.field);
|
||||
debug!("visit_bindings: subpattern_user_ty={:?}", subpattern_user_ty);
|
||||
self.visit_bindings(&subpattern.pattern, &subpattern_user_ty, f);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,11 +79,6 @@ impl<'tcx> PatternTypeProjections<'tcx> {
|
|||
PatternTypeProjections { contents: vec![] }
|
||||
}
|
||||
|
||||
pub(crate) fn ref_binding(&self) -> Self {
|
||||
// FIXME(#55401): ignore for now
|
||||
PatternTypeProjections { contents: vec![] }
|
||||
}
|
||||
|
||||
fn map_projs(&self,
|
||||
mut f: impl FnMut(&PatternTypeProjection<'tcx>) -> PatternTypeProjection<'tcx>)
|
||||
-> Self
|
||||
|
@ -803,7 +798,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
|||
};
|
||||
|
||||
if let Some(user_ty) = self.user_substs_applied_to_ty_of_hir_id(hir_id) {
|
||||
debug!("lower_variant_or_leaf: user_ty={:?} span={:?}", user_ty, span);
|
||||
debug!("lower_variant_or_leaf: kind={:?} user_ty={:?} span={:?}", kind, user_ty, span);
|
||||
kind = PatternKind::AscribeUserType {
|
||||
subpattern: Pattern {
|
||||
span,
|
||||
|
|
|
@ -2388,6 +2388,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
|
||||
pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> {
|
||||
let ty = self.to_ty(ast_ty);
|
||||
debug!("to_ty_saving_user_provided_ty: ty={:?}", ty);
|
||||
|
||||
// If the type given by the user has free regions, save it for
|
||||
// later, since NLL would like to enforce those. Also pass in
|
||||
|
@ -2398,6 +2399,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
// already sufficiently enforced with erased regions. =)
|
||||
if ty.has_free_regions() || ty.has_projections() {
|
||||
let c_ty = self.infcx.canonicalize_response(&UserTypeAnnotation::Ty(ty));
|
||||
debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty);
|
||||
self.tables.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty);
|
||||
}
|
||||
|
||||
|
|
8
src/test/ui/nll/issue-55401.rs
Normal file
8
src/test/ui/nll/issue-55401.rs
Normal file
|
@ -0,0 +1,8 @@
|
|||
#![feature(nll)]
|
||||
|
||||
fn static_to_a_to_static_through_ref_in_tuple<'a>(x: &'a u32) -> &'static u32 {
|
||||
let (ref y, _z): (&'a u32, u32) = (&22, 44);
|
||||
*y //~ ERROR
|
||||
}
|
||||
|
||||
fn main() {}
|
11
src/test/ui/nll/issue-55401.stderr
Normal file
11
src/test/ui/nll/issue-55401.stderr
Normal file
|
@ -0,0 +1,11 @@
|
|||
error: unsatisfied lifetime constraints
|
||||
--> $DIR/issue-55401.rs:5:5
|
||||
|
|
||||
LL | fn static_to_a_to_static_through_ref_in_tuple<'a>(x: &'a u32) -> &'static u32 {
|
||||
| -- lifetime `'a` defined here
|
||||
LL | let (ref y, _z): (&'a u32, u32) = (&22, 44);
|
||||
LL | *y //~ ERROR
|
||||
| ^^ returning this value requires that `'a` must outlive `'static`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
Loading…
Add table
Reference in a new issue