Forbid lifetime elision in let position impl Trait

This is consistent with types.
This commit is contained in:
Matthew Jasper 2020-05-10 12:18:55 +01:00
parent 4201fd273e
commit f97070db90
9 changed files with 95 additions and 52 deletions

View file

@ -1619,15 +1619,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
visitor.visit_ty(ty);
}
}
let parent_def_id = self.current_hir_id_owner.last().unwrap().0;
let ty = l.ty.as_ref().map(|t| {
self.lower_ty(
t,
if self.sess.features_untracked().impl_trait_in_bindings {
ImplTraitContext::OpaqueTy(
Some(parent_def_id.to_def_id()),
hir::OpaqueTyOrigin::Misc,
)
ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Binding)
} else {
ImplTraitContext::Disallowed(ImplTraitPosition::Binding)
},

View file

@ -2018,7 +2018,9 @@ pub enum OpaqueTyOrigin {
FnReturn,
/// `async fn`
AsyncFn,
/// Impl trait in bindings, consts, statics, bounds.
/// `let _: impl Trait = ...`
Binding,
/// Impl trait in type aliases, consts, statics, bounds.
Misc,
}

View file

@ -258,6 +258,9 @@ enum Elide {
Exact(Region),
/// Less or more than one lifetime were found, error on unspecified.
Error(Vec<ElisionFailureInfo>),
/// Forbid lifetime elision inside of a larger scope that does. For
/// example, in let position impl trait.
Forbid,
}
#[derive(Clone, Debug)]
@ -566,7 +569,14 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
// This arm is for `impl Trait` in the types of statics, constants and locals.
hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: None, .. }) => {
intravisit::walk_ty(self, ty);
intravisit::walk_item(this, opaque_ty);
// Elided lifetimes are not allowed in non-return
// position impl Trait
let scope = Scope::Elision { elide: Elide::Forbid, s: self.scope };
self.with(scope, |_, this| {
intravisit::walk_item(this, opaque_ty);
});
return;
}
// RPIT (return position impl trait)
@ -2332,6 +2342,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
}
break Some(e);
}
Elide::Forbid => break None,
};
for lifetime_ref in lifetime_refs {
self.insert_lifetime(lifetime_ref, lifetime);

View file

@ -413,7 +413,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
}
// These opaque type inherit all lifetime parameters from their
// parent.
hir::OpaqueTyOrigin::Misc => 0,
hir::OpaqueTyOrigin::Binding | hir::OpaqueTyOrigin::Misc => 0,
};
let span = tcx.def_span(def_id);
@ -569,7 +569,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
hir::OpaqueTyOrigin::AsyncFn => return false,
// Otherwise, generate the label we'll use in the error message.
hir::OpaqueTyOrigin::TypeAlias
hir::OpaqueTyOrigin::Binding
| hir::OpaqueTyOrigin::FnReturn
| hir::OpaqueTyOrigin::Misc => "impl Trait",
};

View file

@ -100,26 +100,17 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
let substs = InternalSubsts::identity_for_item(tcx, def_id);
tcx.mk_adt(def, substs)
}
ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::Binding, .. }) => {
let_position_impl_trait_type(tcx, def_id.expect_local())
}
ItemKind::OpaqueTy(OpaqueTy { impl_trait_fn: None, .. }) => {
find_opaque_ty_constraints(tcx, def_id.expect_local())
}
// Opaque types desugared from `impl Trait`.
ItemKind::OpaqueTy(OpaqueTy { impl_trait_fn: Some(owner), origin, .. }) => {
let concrete_types = match origin {
OpaqueTyOrigin::FnReturn | OpaqueTyOrigin::AsyncFn => {
&tcx.mir_borrowck(owner.expect_local()).concrete_opaque_types
}
OpaqueTyOrigin::Misc => {
// We shouldn't leak borrowck results through impl trait in bindings.
// For example, we shouldn't be able to tell if `x` in
// `let x: impl Sized + 'a = &()` has type `&'static ()` or `&'a ()`.
&tcx.typeck_tables_of(owner.expect_local()).concrete_opaque_types
}
OpaqueTyOrigin::TypeAlias => {
span_bug!(item.span, "Type alias impl trait shouldn't have an owner")
}
};
let concrete_ty = concrete_types
ItemKind::OpaqueTy(OpaqueTy { impl_trait_fn: Some(owner), .. }) => {
let concrete_ty = tcx
.mir_borrowck(owner.expect_local())
.concrete_opaque_types
.get(&def_id)
.map(|opaque| opaque.concrete_type)
.unwrap_or_else(|| {
@ -148,13 +139,6 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
}
});
debug!("concrete_ty = {:?}", concrete_ty);
if concrete_ty.has_erased_regions() {
// FIXME(impl_trait_in_bindings) Handle this case.
tcx.sess.span_fatal(
item.span,
"lifetimes in impl Trait types in bindings are not currently supported",
);
}
concrete_ty
}
ItemKind::Trait(..)
@ -589,6 +573,50 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
}
}
fn let_position_impl_trait_type(tcx: TyCtxt<'_>, opaque_ty_id: LocalDefId) -> Ty<'_> {
let scope = tcx.hir().get_defining_scope(tcx.hir().as_local_hir_id(opaque_ty_id));
let scope_def_id = tcx.hir().local_def_id(scope);
let opaque_ty_def_id = opaque_ty_id.to_def_id();
let owner_tables = tcx.typeck_tables_of(scope_def_id);
let concrete_ty = owner_tables
.concrete_opaque_types
.get(&opaque_ty_def_id)
.map(|opaque| opaque.concrete_type)
.unwrap_or_else(|| {
tcx.sess.delay_span_bug(
DUMMY_SP,
&format!(
"owner {:?} has no opaque type for {:?} in its tables",
scope_def_id, opaque_ty_id
),
);
if let Some(ErrorReported) = owner_tables.tainted_by_errors {
// Some error in the owner fn prevented us from populating the
// `concrete_opaque_types` table.
tcx.types.err
} else {
// We failed to resolve the opaque type or it resolves to
// itself. Return the non-revealed type, which should result in
// E0720.
tcx.mk_opaque(
opaque_ty_def_id,
InternalSubsts::identity_for_item(tcx, opaque_ty_def_id),
)
}
});
debug!("concrete_ty = {:?}", concrete_ty);
if concrete_ty.has_erased_regions() {
// FIXME(impl_trait_in_bindings) Handle this case.
tcx.sess.span_fatal(
tcx.hir().span(tcx.hir().as_local_hir_id(opaque_ty_id)),
"lifetimes in impl Trait types in bindings are not currently supported",
);
}
concrete_ty
}
fn infer_placeholder_type(
tcx: TyCtxt<'_>,
def_id: LocalDefId,

View file

@ -5,13 +5,11 @@
struct A<'a>(&'a ());
trait Trait<T> {
}
trait Trait<T> {}
impl<T> Trait<T> for () {
}
impl<T> Trait<T> for () {}
fn main() {
let x: impl Trait<A> = (); // FIXME: The error doesn't seem correct.
//~^ ERROR: opaque type expands to a recursive type
let x: impl Trait<A> = ();
//~^ ERROR: missing lifetime specifier
}

View file

@ -1,11 +1,15 @@
error[E0720]: opaque type expands to a recursive type
--> $DIR/issue-60473.rs:15:12
error[E0106]: missing lifetime specifier
--> $DIR/issue-60473.rs:13:23
|
LL | let x: impl Trait<A> = (); // FIXME: The error doesn't seem correct.
| ^^^^^^^^^^^^^ expands to a recursive type
LL | let x: impl Trait<A> = ();
| ^ expected named lifetime parameter
|
help: consider introducing a named lifetime parameter
|
LL | fn main<'a>() {
LL | let x: impl Trait<A<'a>> = ();
|
= note: type resolves to itself
error: aborting due to previous error
For more information about this error, try `rustc --explain E0720`.
For more information about this error, try `rustc --explain E0106`.

View file

@ -4,8 +4,8 @@
#![allow(incomplete_features)]
pub fn run() {
let _foo: Box<impl Copy + '_> = Box::new(()); // FIXME: The error doesn't much make sense.
//~^ ERROR: opaque type expands to a recursive type
let _foo: Box<impl Copy + '_> = Box::new(());
//~^ ERROR: missing lifetime specifier
}
fn main() {}

View file

@ -1,11 +1,15 @@
error[E0720]: opaque type expands to a recursive type
--> $DIR/issue-67166.rs:7:19
error[E0106]: missing lifetime specifier
--> $DIR/issue-67166.rs:7:31
|
LL | let _foo: Box<impl Copy + '_> = Box::new(()); // FIXME: The error doesn't much make sense.
| ^^^^^^^^^^^^^^ expands to a recursive type
LL | let _foo: Box<impl Copy + '_> = Box::new(());
| ^^ expected named lifetime parameter
|
help: consider introducing a named lifetime parameter
|
LL | pub fn run<'a>() {
LL | let _foo: Box<impl Copy + 'a> = Box::new(());
|
= note: type resolves to itself
error: aborting due to previous error
For more information about this error, try `rustc --explain E0720`.
For more information about this error, try `rustc --explain E0106`.