about summary refs log tree commit diff
path: root/compiler/rustc_resolve
diff options
context:
space:
mode:
authorCamille GILLOT <gillot.camille@gmail.com>2022-05-11 22:49:39 +0200
committerCamille GILLOT <gillot.camille@gmail.com>2022-06-21 21:13:41 +0200
commit32af719b07217ff89e61a2031500cee138599baa (patch)
treefef7781b316b4f2fd06655f2892f689032e7b297 /compiler/rustc_resolve
parent4b79b8bfa139ca5f991aa08b405003f748d3caf6 (diff)
downloadrust-32af719b07217ff89e61a2031500cee138599baa.tar.gz
rust-32af719b07217ff89e61a2031500cee138599baa.zip
Always create parameters for functions-like types.
Diffstat (limited to 'compiler/rustc_resolve')
-rw-r--r--compiler/rustc_resolve/src/late.rs193
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs15
-rw-r--r--compiler/rustc_resolve/src/late/lifetimes.rs4
3 files changed, 155 insertions, 57 deletions
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index abccb94a906..08d6134237a 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -21,7 +21,6 @@ use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, PartialRes, PerNS};
 use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
 use rustc_hir::{PrimTy, TraitCandidate};
-use rustc_index::vec::Idx;
 use rustc_middle::ty::DefIdTree;
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
@@ -240,9 +239,16 @@ enum LifetimeRibKind {
     /// Create a new anonymous lifetime parameter and reference it.
     ///
     /// If `report_in_path`, report an error when encountering lifetime elision in a path:
-    /// ```ignore
-    /// struct Foo<'a> { .. }
-    /// fn foo(x: Foo) {}
+    /// ```compile_fail
+    /// struct Foo<'a> { x: &'a () }
+    /// async fn foo(x: Foo) {}
+    /// ```
+    ///
+    /// Note: the error should not trigger when the elided lifetime is in a pattern or
+    /// expression-position path:
+    /// ```
+    /// struct Foo<'a> { x: &'a () }
+    /// async fn foo(Foo { x: _ }: Foo<'_>) {}
     /// ```
     AnonymousCreateParameter { binder: NodeId, report_in_path: bool },
 
@@ -634,7 +640,10 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
                     |this| {
                         this.visit_generic_params(&bare_fn.generic_params, false);
                         this.with_lifetime_rib(
-                            LifetimeRibKind::AnonymousPassThrough(ty.id, false),
+                            LifetimeRibKind::AnonymousCreateParameter {
+                                binder: ty.id,
+                                report_in_path: false,
+                            },
                             |this| walk_list!(this, visit_param, &bare_fn.decl.inputs),
                         );
                         this.with_lifetime_rib(
@@ -720,15 +729,13 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
             // a body, or if there's no body for some other reason.
             FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _)
             | FnKind::Fn(_, _, sig, _, generics, None) => {
+                self.visit_fn_header(&sig.header);
+                self.visit_generics(generics);
                 // We don't need to deal with patterns in parameters, because
                 // they are not possible for foreign or bodiless functions.
                 self.with_lifetime_rib(
                     LifetimeRibKind::AnonymousPassThrough(fn_id, false),
-                    |this| {
-                        this.visit_fn_header(&sig.header);
-                        this.visit_generics(generics);
-                        walk_list!(this, visit_param, &sig.decl.inputs);
-                    },
+                    |this| walk_list!(this, visit_param, &sig.decl.inputs),
                 );
                 self.with_lifetime_rib(
                     LifetimeRibKind::AnonymousPassThrough(fn_id, true),
@@ -761,15 +768,18 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
                         // generic parameters.  This is especially useful for `async fn`, where
                         // these fresh generic parameters can be applied to the opaque `impl Trait`
                         // return type.
+                        let rib = if async_node_id.is_some() {
+                            // Only emit a hard error for `async fn`, since this kind of
+                            // elision has always been allowed in regular `fn`s.
+                            LifetimeRibKind::AnonymousCreateParameter {
+                                binder: fn_id,
+                                report_in_path: true,
+                            }
+                        } else {
+                            LifetimeRibKind::AnonymousPassThrough(fn_id, false)
+                        };
                         this.with_lifetime_rib(
-                            if async_node_id.is_some() {
-                                LifetimeRibKind::AnonymousCreateParameter {
-                                    binder: fn_id,
-                                    report_in_path: true,
-                                }
-                            } else {
-                                LifetimeRibKind::AnonymousPassThrough(fn_id, false)
-                            },
+                            rib,
                             // Add each argument to the rib.
                             |this| this.resolve_params(&declaration.inputs),
                         );
@@ -937,19 +947,66 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
         self.diagnostic_metadata.currently_processing_generics = prev;
     }
 
+    fn visit_assoc_constraint(&mut self, constraint: &'ast AssocConstraint) {
+        self.visit_ident(constraint.ident);
+        if let Some(ref gen_args) = constraint.gen_args {
+            // Forbid anonymous lifetimes in GAT parameters until proper semantics are decided.
+            self.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
+                this.visit_generic_args(gen_args.span(), gen_args)
+            });
+        }
+        match constraint.kind {
+            AssocConstraintKind::Equality { ref term } => match term {
+                Term::Ty(ty) => self.visit_ty(ty),
+                Term::Const(c) => self.visit_anon_const(c),
+            },
+            AssocConstraintKind::Bound { ref bounds } => {
+                walk_list!(self, visit_param_bound, bounds, BoundKind::Bound);
+            }
+        }
+    }
+
     fn visit_path_segment(&mut self, path_span: Span, path_segment: &'ast PathSegment) {
         if let Some(ref args) = path_segment.args {
             match &**args {
                 GenericArgs::AngleBracketed(..) => visit::walk_generic_args(self, path_span, args),
-                GenericArgs::Parenthesized(ref data) => {
-                    self.with_lifetime_rib(
-                        LifetimeRibKind::AnonymousPassThrough(path_segment.id, false),
-                        |this| walk_list!(this, visit_ty, &data.inputs),
-                    );
-                    self.with_lifetime_rib(
-                        LifetimeRibKind::AnonymousPassThrough(path_segment.id, true),
-                        |this| visit::walk_fn_ret_ty(this, &data.output),
-                    )
+                GenericArgs::Parenthesized(p_args) => {
+                    // Probe the lifetime ribs to know how to behave.
+                    for rib in self.lifetime_ribs.iter().rev() {
+                        match rib.kind {
+                            // We are inside a `PolyTraitRef`.  The lifetimes are
+                            // to be intoduced in that (maybe implicit) `for<>` binder.
+                            LifetimeRibKind::Generics {
+                                binder,
+                                kind: LifetimeBinderKind::PolyTrait,
+                                ..
+                            } => {
+                                self.with_lifetime_rib(
+                                    LifetimeRibKind::AnonymousCreateParameter {
+                                        binder,
+                                        report_in_path: false,
+                                    },
+                                    |this| walk_list!(this, visit_ty, &p_args.inputs),
+                                );
+                                self.with_lifetime_rib(
+                                    LifetimeRibKind::AnonymousPassThrough(binder, true),
+                                    |this| visit::walk_fn_ret_ty(this, &p_args.output),
+                                );
+                                break;
+                            }
+                            // We have nowhere to introduce generics.  Code is malformed,
+                            // so use regular lifetime resolution to avoid spurious errors.
+                            LifetimeRibKind::Item | LifetimeRibKind::Generics { .. } => {
+                                visit::walk_generic_args(self, path_span, args);
+                                break;
+                            }
+                            LifetimeRibKind::AnonymousPassThrough(..)
+                            | LifetimeRibKind::AnonymousCreateParameter { .. }
+                            | LifetimeRibKind::AnonymousReportError
+                            | LifetimeRibKind::AnonConst
+                            | LifetimeRibKind::ConstGeneric => {}
+                        }
+                    }
                 }
             }
         }
@@ -1474,7 +1531,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 continue;
             }
 
-            let mut should_lint = match source {
+            let missing = match source {
                 PathSource::Trait(..) | PathSource::TraitItem(..) | PathSource::Type => true,
                 PathSource::Expr(..)
                 | PathSource::Pat
@@ -1499,6 +1556,39 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 LifetimeRes::ElidedAnchor { start: node_ids.start, end: node_ids.end },
             );
 
+            if !missing {
+                // Do not create a parameter for patterns and expressions.
+                for rib in self.lifetime_ribs.iter().rev() {
+                    match rib.kind {
+                        LifetimeRibKind::AnonymousPassThrough(binder, _) => {
+                            let res = LifetimeRes::Anonymous { binder, elided: true };
+                            for id in node_ids {
+                                self.record_lifetime_res(id, res);
+                            }
+                            break;
+                        }
+                        // `LifetimeRes::Error`, which would usually be used in the case of
+                        // `ReportError`, is unsuitable here, as we don't emit an error yet.  Instead,
+                        // we simply resolve to an implicit lifetime, which will be checked later, at
+                        // which point a suitable error will be emitted.
+                        LifetimeRibKind::AnonymousReportError | LifetimeRibKind::Item => {
+                            // FIXME(cjgillot) This resolution is wrong, but this does not matter
+                            // since these cases are erroneous anyway.  Lifetime resolution should
+                            // emit a "missing lifetime specifier" diagnostic.
+                            let res =
+                                LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true };
+                            for id in node_ids {
+                                self.record_lifetime_res(id, res);
+                            }
+                            break;
+                        }
+                        _ => {}
+                    }
+                }
+                continue;
+            }
+
+            let mut should_lint = true;
             for rib in self.lifetime_ribs.iter().rev() {
                 match rib.kind {
                     // In create-parameter mode we error here because we don't want to support
@@ -1526,44 +1616,38 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                         err.note("assuming a `'static` lifetime...");
                         err.emit();
                         should_lint = false;
-                        for i in 0..expected_lifetimes {
-                            let id = node_ids.start.plus(i);
+
+                        for id in node_ids {
                             self.record_lifetime_res(id, LifetimeRes::Error);
                         }
                         break;
                     }
+                    // Do not create a parameter for patterns and expressions.
                     LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
-                        let res = self.create_fresh_lifetime(node_ids.start, ident, binder);
-                        self.record_lifetime_res(node_ids.start, res);
-                        for i in 1..expected_lifetimes {
-                            let id = node_ids.start.plus(i);
+                        for id in node_ids {
                             let res = self.create_fresh_lifetime(id, ident, binder);
                             self.record_lifetime_res(id, res);
                         }
                         break;
                     }
                     // `PassThrough` is the normal case.
-                    // `new_error_lifetime`, which would usually be used in the case of `ReportError`,
-                    // is unsuitable here, as these can occur from missing lifetime parameters in a
-                    // `PathSegment`, for which there is no associated `'_` or `&T` with no explicit
-                    // lifetime. Instead, we simply create an implicit lifetime, which will be checked
-                    // later, at which point a suitable error will be emitted.
                     LifetimeRibKind::AnonymousPassThrough(binder, _) => {
                         let res = LifetimeRes::Anonymous { binder, elided: true };
-                        self.record_lifetime_res(node_ids.start, res);
-                        for i in 1..expected_lifetimes {
-                            let id = node_ids.start.plus(i);
+                        for id in node_ids {
                             self.record_lifetime_res(id, res);
                         }
                         break;
                     }
+                    // `LifetimeRes::Error`, which would usually be used in the case of
+                    // `ReportError`, is unsuitable here, as we don't emit an error yet.  Instead,
+                    // we simply resolve to an implicit lifetime, which will be checked later, at
+                    // which point a suitable error will be emitted.
                     LifetimeRibKind::AnonymousReportError | LifetimeRibKind::Item => {
                         // FIXME(cjgillot) This resolution is wrong, but this does not matter
                         // since these cases are erroneous anyway.  Lifetime resolution should
                         // emit a "missing lifetime specifier" diagnostic.
                         let res = LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true };
-                        for i in 0..expected_lifetimes {
-                            let id = node_ids.start.plus(i);
+                        for id in node_ids {
                             self.record_lifetime_res(id, res);
                         }
                         break;
@@ -2235,7 +2319,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
     fn resolve_impl_item(&mut self, item: &'ast AssocItem) {
         use crate::ResolutionError::*;
         match &item.kind {
-            AssocItemKind::Const(_default, _ty, _expr) => {
+            AssocItemKind::Const(_, ty, default) => {
                 debug!("resolve_implementation AssocItemKind::Const");
                 // If this is a trait impl, ensure the const
                 // exists in trait
@@ -2248,14 +2332,17 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                     |i, s, c| ConstNotMemberOfTrait(i, s, c),
                 );
 
-                // We allow arbitrary const expressions inside of associated consts,
-                // even if they are potentially not const evaluatable.
-                //
-                // Type parameters can already be used and as associated consts are
-                // not used as part of the type system, this is far less surprising.
-                self.with_constant_rib(IsRepeatExpr::No, HasGenericParams::Yes, None, |this| {
-                    visit::walk_assoc_item(this, item, AssocCtxt::Impl)
-                });
+                self.visit_ty(ty);
+                if let Some(expr) = default {
+                    // We allow arbitrary const expressions inside of associated consts,
+                    // even if they are potentially not const evaluatable.
+                    //
+                    // Type parameters can already be used and as associated consts are
+                    // not used as part of the type system, this is far less surprising.
+                    self.with_constant_rib(IsRepeatExpr::No, HasGenericParams::Yes, None, |this| {
+                        this.visit_expr(expr)
+                    });
+                }
             }
             AssocItemKind::Fn(box Fn { generics, .. }) => {
                 debug!("resolve_implementation AssocItemKind::Fn");
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 1a99bff610a..15f862e21d7 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -2223,9 +2223,18 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
             ]
             .contains(&Some(did))
             {
-                let (span, span_type) = match &trait_ref.bound_generic_params {
-                    [] => (trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty),
-                    [.., bound] => (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail),
+                let (span, span_type) = if let Some(bound) =
+                    trait_ref.bound_generic_params.iter().rfind(|param| {
+                        matches!(
+                            param.kind,
+                            hir::GenericParamKind::Lifetime {
+                                kind: hir::LifetimeParamKind::Explicit
+                            }
+                        )
+                    }) {
+                    (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail)
+                } else {
+                    (trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty)
                 };
                 self.missing_named_lifetime_spots
                     .push(MissingLifetimeSpot::HigherRanked { span, span_type });
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index 447f4174c10..53f6870bdf5 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -755,7 +755,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 let next_early_index = self.next_early_index();
                 let lifetime_span: Option<Span> =
                     c.generic_params.iter().rev().find_map(|param| match param.kind {
-                        GenericParamKind::Lifetime { .. } => Some(param.span),
+                        GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit } => {
+                            Some(param.span)
+                        }
                         _ => None,
                     });
                 let (span, span_type) = if let Some(span) = lifetime_span {