Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Account for late-bound vars from parent arg-position impl trait #113071

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,15 @@ hir_analysis_invalid_union_field =
hir_analysis_invalid_union_field_sugg =
wrap the field type in `ManuallyDrop<...>`

hir_analysis_late_bound_const_in_apit = `impl Trait` can only mention const parameters from an fn or impl
.label = const parameter declared here

hir_analysis_late_bound_lifetime_in_apit = `impl Trait` can only mention lifetimes from an fn or impl
.label = lifetime declared here

hir_analysis_late_bound_type_in_apit = `impl Trait` can only mention type parameters from an fn or impl
.label = type parameter declared here

hir_analysis_lifetimes_or_bounds_mismatch_on_trait =
lifetime parameters or bounds on {$item_kind} `{$ident}` do not match the trait declaration
.label = lifetimes do not match {$item_kind} in trait
Expand Down
55 changes: 49 additions & 6 deletions compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1344,12 +1344,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
Scope::Binder {
where_bound_origin: Some(hir::PredicateOrigin::ImplTrait), ..
} => {
let mut err = self.tcx.sess.struct_span_err(
lifetime_ref.ident.span,
"`impl Trait` can only mention lifetimes bound at the fn or impl level",
);
err.span_note(self.tcx.def_span(region_def_id), "lifetime declared here");
err.emit();
self.tcx.sess.emit_err(errors::LateBoundInApit::Lifetime {
span: lifetime_ref.ident.span,
param_span: self.tcx.def_span(region_def_id),
});
return;
}
Scope::Root { .. } => break,
Expand Down Expand Up @@ -1379,6 +1377,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
let mut late_depth = 0;
let mut scope = self.scope;
let mut crossed_anon_const = false;

let result = loop {
match *scope {
Scope::Body { s, .. } => {
Expand Down Expand Up @@ -1446,6 +1445,50 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
return;
}

// We may fail to resolve higher-ranked ty/const vars that are mentioned by APIT.
// AST-based resolution does not care for impl-trait desugaring, which are the
// responsibility of lowering. This may create a mismatch between the resolution
// AST found (`param_def_id`) which points to HRTB, and what HIR allows.
// ```
// fn foo(x: impl for<T> Trait<Assoc = impl Trait2<T>>) {}
// ```
//
// In such case, walk back the binders to diagnose it properly.
let mut scope = self.scope;
loop {
match *scope {
Scope::Binder {
where_bound_origin: Some(hir::PredicateOrigin::ImplTrait), ..
} => {
let guar = self.tcx.sess.emit_err(match self.tcx.def_kind(param_def_id) {
DefKind::TyParam => errors::LateBoundInApit::Type {
span: self.tcx.hir().span(hir_id),
param_span: self.tcx.def_span(param_def_id),
},
DefKind::ConstParam => errors::LateBoundInApit::Const {
span: self.tcx.hir().span(hir_id),
param_span: self.tcx.def_span(param_def_id),
},
kind => {
bug!("unexpected def-kind: {}", kind.descr(param_def_id.to_def_id()))
}
});
self.map.defs.insert(hir_id, ResolvedArg::Error(guar));
return;
}
Scope::Root { .. } => break,
Scope::Binder { s, .. }
| Scope::Body { s, .. }
| Scope::Elision { s, .. }
| Scope::ObjectLifetimeDefault { s, .. }
| Scope::Supertrait { s, .. }
| Scope::TraitRefBoundary { s, .. }
| Scope::AnonConstBoundary { s } => {
scope = s;
}
}
}

self.tcx.sess.delay_span_bug(
self.tcx.hir().span(hir_id),
format!("could not resolve {param_def_id:?}"),
Expand Down
25 changes: 25 additions & 0 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -875,3 +875,28 @@ pub(crate) enum ReturnTypeNotationIllegalParam {
param_span: Span,
},
}

#[derive(Diagnostic)]
pub(crate) enum LateBoundInApit {
#[diag(hir_analysis_late_bound_type_in_apit)]
Type {
#[primary_span]
span: Span,
#[label]
param_span: Span,
},
#[diag(hir_analysis_late_bound_const_in_apit)]
Const {
#[primary_span]
span: Span,
#[label]
param_span: Span,
},
#[diag(hir_analysis_late_bound_lifetime_in_apit)]
Lifetime {
#[primary_span]
span: Span,
#[label]
param_span: Span,
},
}
2 changes: 1 addition & 1 deletion tests/ui/impl-trait/universal_wrong_hrtb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ trait Trait<'a> {
}

fn test_argument_position(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {}
//~^ ERROR `impl Trait` can only mention lifetimes bound at the fn or impl level
//~^ ERROR `impl Trait` can only mention lifetimes from an fn or impl

fn main() {}
10 changes: 2 additions & 8 deletions tests/ui/impl-trait/universal_wrong_hrtb.stderr
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
error: `impl Trait` can only mention lifetimes bound at the fn or impl level
error: `impl Trait` can only mention lifetimes from an fn or impl
--> $DIR/universal_wrong_hrtb.rs:5:73
|
LL | fn test_argument_position(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {}
| ^^
|
note: lifetime declared here
--> $DIR/universal_wrong_hrtb.rs:5:39
|
LL | fn test_argument_position(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {}
| ^^
| -- lifetime declared here ^^

error: aborting due to previous error

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#![feature(non_lifetime_binders)]
//~^ WARN the feature `non_lifetime_binders` is incomplete

trait Trait<Input> {
type Assoc;
}

fn uwu(_: impl for<T> Trait<(), Assoc = impl Trait<T>>) {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh, I didn't even know for<T> was a thing!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

//~^ ERROR `impl Trait` can only mention type parameters from an fn or impl

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/nested-apit-mentioning-outer-bound-var.rs:1:12
|
LL | #![feature(non_lifetime_binders)]
| ^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
= note: `#[warn(incomplete_features)]` on by default

error: `impl Trait` can only mention type parameters from an fn or impl
--> $DIR/nested-apit-mentioning-outer-bound-var.rs:8:52
|
LL | fn uwu(_: impl for<T> Trait<(), Assoc = impl Trait<T>>) {}
| - type parameter declared here ^

error: aborting due to previous error; 1 warning emitted