diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index ace20a005ee4..0cf96797028d 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2188,12 +2188,12 @@ pub enum TraitObjectSyntax { None, } -#[derive(Clone, PartialEq, Encodable, Decodable, Debug)] +#[derive(Clone, Encodable, Decodable, Debug)] pub enum PreciseCapturingArg { /// Lifetime parameter Lifetime(Lifetime), /// Type or const parameter - Arg(Ident, NodeId), + Arg(Path, NodeId), } /// Inline assembly operand explicit register or register class. diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 204f33cab345..c4e49d7dbea4 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -928,8 +928,8 @@ pub fn noop_visit_precise_capturing_arg(arg: &mut PreciseCapturin PreciseCapturingArg::Lifetime(lt) => { vis.visit_lifetime(lt); } - PreciseCapturingArg::Arg(ident, id) => { - vis.visit_ident(ident); + PreciseCapturingArg::Arg(path, id) => { + vis.visit_path(path); vis.visit_id(id); } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index a9c29e077d13..968d10ad4872 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -653,8 +653,8 @@ pub fn walk_precise_capturing_arg<'a, V: Visitor<'a>>( PreciseCapturingArg::Lifetime(lt) => { visitor.visit_lifetime(lt, LifetimeCtxt::GenericArg); } - PreciseCapturingArg::Arg(ident, _) => { - visitor.visit_ident(*ident); + PreciseCapturingArg::Arg(path, id) => { + visitor.visit_path(path, *id); } } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 84776f920c46..a21d6019cf16 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1790,13 +1790,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { PreciseCapturingArg::Lifetime(lt) => { hir::PreciseCapturingArg::Lifetime(self.lower_lifetime(lt)) } - PreciseCapturingArg::Arg(ident, node_id) => { - let res = self.resolver.get_partial_res(*node_id).map_or(Res::Err, |partial_res| { + PreciseCapturingArg::Arg(path, id) => { + let [segment] = path.segments.as_slice() else { + panic!(); + }; + let res = self.resolver.get_partial_res(*id).map_or(Res::Err, |partial_res| { partial_res.full_res().expect("no partial res expected for precise capture arg") }); hir::PreciseCapturingArg::Param(hir::PreciseCapturingNonLifetimeArg { - hir_id: self.lower_node_id(*node_id), - ident: self.lower_ident(*ident), + hir_id: self.lower_node_id(*id), + ident: self.lower_ident(segment.ident), res: self.lower_res(res), }) } diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index db9633bb1cbb..969099409723 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1156,7 +1156,7 @@ impl<'a> State<'a> { self.word("use"); self.word("<"); self.commasep(Inconsistent, precise_capturing_args, |s, arg| match arg { - ast::PreciseCapturingArg::Arg(a, _) => s.print_ident(*a), + ast::PreciseCapturingArg::Arg(p, _) => s.print_path(p, false, 0), ast::PreciseCapturingArg::Lifetime(lt) => s.print_lifetime(*lt), }); self.word(">") diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 4ac2965bd5f0..bc6583444c33 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -39,6 +39,9 @@ hir_analysis_auto_deref_reached_recursion_limit = reached the recursion limit wh hir_analysis_bad_precise_capture = expected {$kind} parameter in `use<...>` precise captures list, found {$found} +hir_analysis_precise_capture_self_alias = `Self` can't be captured in `use<...>` precise captures list, since it is an alias + .label = `Self` is not a generic argument, but an alias to the type of the {$what} + hir_analysis_cannot_capture_late_bound_const = cannot capture late-bound const parameter in {$what} .label = parameter defined here diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index fb3713140ffe..78c2665fd1f3 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -583,9 +583,19 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { self.resolve_type_ref(def_id.expect_local(), param.hir_id); } Res::Err => {} - _ => { - // This is handled in resolve - self.tcx.dcx().delayed_bug(format!("parameter should have been resolved")); + Res::SelfTyAlias { alias_to, .. } => { + self.tcx.dcx().emit_err(errors::PreciseCaptureSelfAlias { + span: param.ident.span, + self_span: self.tcx.def_span(alias_to), + what: self.tcx.def_descr(alias_to), + }); + } + res => { + self.tcx.dcx().emit_err(errors::BadPreciseCapture { + span: param.ident.span, + kind: "type or const", + found: res.descr().to_string(), + }); } }, } diff --git a/compiler/rustc_hir_analysis/src/errors/precise_captures.rs b/compiler/rustc_hir_analysis/src/errors/precise_captures.rs index e2eb9c72bf23..520bf1d9f404 100644 --- a/compiler/rustc_hir_analysis/src/errors/precise_captures.rs +++ b/compiler/rustc_hir_analysis/src/errors/precise_captures.rs @@ -32,6 +32,16 @@ pub struct BadPreciseCapture { pub found: String, } +#[derive(Diagnostic)] +#[diag(hir_analysis_precise_capture_self_alias)] +pub struct PreciseCaptureSelfAlias { + #[primary_span] + pub span: Span, + #[label] + pub self_span: Span, + pub what: &'static str, +} + #[derive(Diagnostic)] #[diag(hir_analysis_duplicate_precise_capture)] pub struct DuplicatePreciseCapture { diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 91f4823f65d4..f78a039394b8 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -697,11 +697,14 @@ impl<'a> Parser<'a> { if self_.check_keyword(kw::SelfUpper) { self_.bump(); Ok(PreciseCapturingArg::Arg( - self_.prev_token.ident().unwrap().0, + ast::Path::from_ident(self_.prev_token.ident().unwrap().0), DUMMY_NODE_ID, )) } else if self_.check_ident() { - Ok(PreciseCapturingArg::Arg(self_.parse_ident().unwrap(), DUMMY_NODE_ID)) + Ok(PreciseCapturingArg::Arg( + ast::Path::from_ident(self_.parse_ident()?), + DUMMY_NODE_ID, + )) } else if self_.check_lifetime() { Ok(PreciseCapturingArg::Lifetime(self_.expect_lifetime())) } else { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 7203adab135a..64434412886b 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1056,64 +1056,22 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, match arg { // Lower the lifetime regularly; we'll resolve the lifetime and check // it's a parameter later on in HIR lowering. - PreciseCapturingArg::Lifetime(_) => visit::walk_precise_capturing_arg(self, arg), + PreciseCapturingArg::Lifetime(_) => {} - PreciseCapturingArg::Arg(ident, node_id) => { - let ident = ident.normalize_to_macros_2_0(); - 'found: { - for (rib_t, rib_v) in - std::iter::zip(&self.ribs.type_ns, &self.ribs.value_ns).rev() - { - if let Some(res) = rib_t.bindings.get(&ident).or(rib_v.bindings.get(&ident)) - { - self.r.record_partial_res(*node_id, PartialRes::new(*res)); - - // Validate that this is a parameter - match res { - Res::Def(DefKind::TyParam | DefKind::ConstParam, _) - | Res::SelfTyParam { .. } => {} - Res::SelfTyAlias { .. } => { - self.report_error( - ident.span, - ResolutionError::FailedToResolve { - segment: Some(ident.name), - label: "`Self` cannot be captured because it is not a type parameter".to_string(), - suggestion: None, - module: None, - }, - ); - } - _ => { - self.report_error( - ident.span, - ResolutionError::FailedToResolve { - segment: Some(ident.name), - label: format!( - "expected type or const parameter, found {}", - res.descr() - ), - suggestion: None, - module: None, - }, - ); - } - } - - break 'found; - } - } - self.report_error( - ident.span, - ResolutionError::FailedToResolve { - segment: Some(ident.name), - label: "could not find type or const parameter".to_string(), - suggestion: None, - module: None, - }, - ); + PreciseCapturingArg::Arg(path, id) => { + let mut check_ns = |ns| { + self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns).is_some() + }; + // Like `Ty::Param`, we try resolving this as both a const and a type. + if !check_ns(TypeNS) && check_ns(ValueNS) { + self.smart_resolve_path(*id, &None, path, PathSource::Expr(None)); + } else { + self.smart_resolve_path(*id, &None, path, PathSource::Type); } } } + + visit::walk_precise_capturing_arg(self, arg) } fn visit_generics(&mut self, generics: &'ast Generics) { diff --git a/tests/ui/impl-trait/precise-capturing/bad-params.rs b/tests/ui/impl-trait/precise-capturing/bad-params.rs index c600fa96f794..195bd1b67aeb 100644 --- a/tests/ui/impl-trait/precise-capturing/bad-params.rs +++ b/tests/ui/impl-trait/precise-capturing/bad-params.rs @@ -2,15 +2,15 @@ //~^ WARN the feature `precise_capturing` is incomplete fn missing() -> impl use Sized {} -//~^ ERROR could not find type or const parameter +//~^ ERROR cannot find type `T` in this scope fn missing_self() -> impl use Sized {} -//~^ ERROR could not find type or const parameter +//~^ ERROR cannot find type `Self` in this scope struct MyType; impl MyType { fn self_is_not_param() -> impl use Sized {} - //~^ ERROR `Self` cannot be captured because it is not a type parameter + //~^ ERROR `Self` can't be captured in `use<...>` precise captures list, since it is an alias } fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/bad-params.stderr b/tests/ui/impl-trait/precise-capturing/bad-params.stderr index bb5fe76ae3e3..09694a800c41 100644 --- a/tests/ui/impl-trait/precise-capturing/bad-params.stderr +++ b/tests/ui/impl-trait/precise-capturing/bad-params.stderr @@ -1,20 +1,21 @@ -error[E0433]: failed to resolve: could not find type or const parameter +error[E0412]: cannot find type `T` in this scope --> $DIR/bad-params.rs:4:26 | LL | fn missing() -> impl use Sized {} - | ^ could not find type or const parameter + | ^ not found in this scope + | +help: you might be missing a type parameter + | +LL | fn missing() -> impl use Sized {} + | +++ -error[E0433]: failed to resolve: could not find type or const parameter +error[E0411]: cannot find type `Self` in this scope --> $DIR/bad-params.rs:7:31 | LL | fn missing_self() -> impl use Sized {} - | ^^^^ could not find type or const parameter - -error[E0433]: failed to resolve: `Self` cannot be captured because it is not a type parameter - --> $DIR/bad-params.rs:12:40 - | -LL | fn self_is_not_param() -> impl use Sized {} - | ^^^^ `Self` cannot be captured because it is not a type parameter + | ------------ ^^^^ `Self` is only available in impls, traits, and type definitions + | | + | `Self` not allowed in a function warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/bad-params.rs:1:12 @@ -25,6 +26,15 @@ LL | #![feature(precise_capturing)] = note: see issue #123432 for more information = note: `#[warn(incomplete_features)]` on by default +error: `Self` can't be captured in `use<...>` precise captures list, since it is an alias + --> $DIR/bad-params.rs:12:40 + | +LL | impl MyType { + | ----------- `Self` is not a generic argument, but an alias to the type of the implementation +LL | fn self_is_not_param() -> impl use Sized {} + | ^^^^ + error: aborting due to 3 previous errors; 1 warning emitted -For more information about this error, try `rustc --explain E0433`. +Some errors have detailed explanations: E0411, E0412. +For more information about an error, try `rustc --explain E0411`.