Skip to content
Open
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: 8 additions & 1 deletion compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,14 @@ pub(crate) struct RustcObjectLifetimeDefaultParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcObjectLifetimeDefaultParser {
const PATH: &[Symbol] = &[sym::rustc_object_lifetime_default];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Struct),
Allow(Target::Enum),
Allow(Target::Union),
Allow(Target::Trait),
Allow(Target::TyAlias),
Allow(Target::AssocTy),
]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcObjectLifetimeDefault;
}

Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -707,12 +707,12 @@ impl<'hir> GenericArgs<'hir> {
}

#[inline]
pub fn num_lifetime_params(&self) -> usize {
pub fn num_lifetime_args(&self) -> usize {
self.args.iter().filter(|arg| matches!(arg, GenericArg::Lifetime(_))).count()
}

#[inline]
pub fn has_lifetime_params(&self) -> bool {
pub fn has_lifetime_args(&self) -> bool {
self.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)))
}

Expand Down
464 changes: 284 additions & 180 deletions compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
AngleBrackets::Missing => 0,
// Only lifetime arguments can be implied
AngleBrackets::Implied => self.gen_args.args.len(),
AngleBrackets::Available => self.gen_args.num_lifetime_params(),
AngleBrackets::Available => self.gen_args.num_lifetime_args(),
}
}

Expand Down
12 changes: 6 additions & 6 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ pub(crate) fn check_generic_arg_count(
let named_type_param_count = param_counts.types - has_self as usize - synth_type_param_count;
let named_const_param_count = param_counts.consts;
let infer_lifetimes =
(gen_pos != GenericArgPosition::Type || seg.infer_args) && !gen_args.has_lifetime_params();
(gen_pos != GenericArgPosition::Type || seg.infer_args) && !gen_args.has_lifetime_args();

if gen_pos != GenericArgPosition::Type
&& let Some(c) = gen_args.constraints.first()
Expand Down Expand Up @@ -471,7 +471,7 @@ pub(crate) fn check_generic_arg_count(

let min_expected_lifetime_args = if infer_lifetimes { 0 } else { param_counts.lifetimes };
let max_expected_lifetime_args = param_counts.lifetimes;
let num_provided_lifetime_args = gen_args.num_lifetime_params();
let num_provided_lifetime_args = gen_args.num_lifetime_args();

let lifetimes_correct = check_lifetime_args(
min_expected_lifetime_args,
Expand Down Expand Up @@ -595,7 +595,7 @@ pub(crate) fn check_generic_arg_count(
- default_counts.consts
};
debug!(?expected_min);
debug!(arg_counts.lifetimes=?gen_args.num_lifetime_params());
debug!(arg_counts.lifetimes=?gen_args.num_lifetime_args());

let provided = gen_args.num_generic_params();

Expand All @@ -605,7 +605,7 @@ pub(crate) fn check_generic_arg_count(
named_const_param_count + named_type_param_count + synth_type_param_count,
provided,
param_counts.lifetimes + has_self as usize,
gen_args.num_lifetime_params(),
gen_args.num_lifetime_args(),
)
};

Expand All @@ -628,15 +628,15 @@ pub(crate) fn prohibit_explicit_late_bound_lifetimes(
let param_counts = def.own_counts();

if let Some(span_late) = def.has_late_bound_regions
&& args.has_lifetime_params()
&& args.has_lifetime_args()
{
let msg = "cannot specify lifetime arguments explicitly \
if late bound lifetime parameters are present";
let note = "the late bound lifetime parameter is introduced here";
let span = args.args[0].span();

if position == GenericArgPosition::Value
&& args.num_lifetime_params() != param_counts.lifetimes
&& args.num_lifetime_args() != param_counts.lifetimes
{
struct_span_code_err!(cx.dcx(), span, E0794, "{}", msg)
.with_span_note(span_late, note)
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1527,7 +1527,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
if let Some(name) = tcx.intrinsic(def_id) {
record!(self.tables.intrinsic[def_id] <- name);
}
if let DefKind::TyParam = def_kind {
if let DefKind::TyParam | DefKind::Trait = def_kind {
let default = self.tcx.object_lifetime_default(def_id);
record!(self.tables.object_lifetime_default[def_id] <- default);
}
Expand Down
26 changes: 12 additions & 14 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -758,20 +758,18 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
/// Debugging aid for `object_lifetime_default` query.
fn check_object_lifetime_default(&self, hir_id: HirId) {
let tcx = self.tcx;
if let Some(owner_id) = hir_id.as_owner()
&& let Some(generics) = tcx.hir_get_generics(owner_id.def_id)
{
for p in generics.params {
let hir::GenericParamKind::Type { .. } = p.kind else { continue };
let default = tcx.object_lifetime_default(p.def_id);
let repr = match default {
ObjectLifetimeDefault::Empty => "BaseDefault".to_owned(),
ObjectLifetimeDefault::Static => "'static".to_owned(),
ObjectLifetimeDefault::Param(def_id) => tcx.item_name(def_id).to_string(),
ObjectLifetimeDefault::Ambiguous => "Ambiguous".to_owned(),
};
tcx.dcx().emit_err(errors::ObjectLifetimeErr { span: p.span, repr });
}
let Some(owner_id) = hir_id.as_owner() else { return };
for param in &tcx.generics_of(owner_id.def_id).own_params {
let ty::GenericParamDefKind::Type { .. } = param.kind else { continue };
let default = tcx.object_lifetime_default(param.def_id);
let repr = match default {
ObjectLifetimeDefault::Empty => "Empty".to_owned(),
ObjectLifetimeDefault::Static => "'static".to_owned(),
ObjectLifetimeDefault::Param(def_id) => tcx.item_name(def_id).to_string(),
ObjectLifetimeDefault::Ambiguous => "Ambiguous".to_owned(),
};
tcx.dcx()
.emit_err(errors::ObjectLifetimeErr { span: tcx.def_span(param.def_id), repr });
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1989,6 +1989,9 @@ impl<'tcx> ContainerTy<'_, 'tcx> {
match self {
Self::Ref(region) => ObjectLifetimeDefault::Arg(region),
Self::Regular { ty: container, args, arg: index } => {
// FIXME(fmease): Since #129543 assoc tys can now also induce trait object
// lifetime defaults. Re-elide these, too!

let (DefKind::Struct
| DefKind::Union
| DefKind::Enum
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/deriving/issue-89188-gat-hrtb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ trait Trait<'s, 't, 'u> {}
#[derive(Clone)]
struct ShimMethod3<T: CallWithShim2 + 'static>(
pub &'static dyn for<'s> Fn(
&'s mut T::Shim<dyn for<'t> Fn(&'s mut T::Shim<dyn for<'u> Trait<'s, 't, 'u>>)>,
&'s mut T::Shim<dyn for<'t> Fn(&'s mut T::Shim<dyn for<'u> Trait<'s, 't, 'u> + 's>) + 's>,
),
);

Expand Down
16 changes: 6 additions & 10 deletions tests/ui/did_you_mean/bad-assoc-ty.edition2015.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -193,20 +193,16 @@ help: if this is a dyn-compatible trait, use `dyn`
LL | type H = <dyn Fn(u8) -> (u8)>::Output;
| ++++ +

error[E0223]: ambiguous associated type
error[E0228]: cannot deduce the lifetime bound for this trait object type from context
--> $DIR/bad-assoc-ty.rs:37:10
|
LL | type H = Fn(u8) -> (u8)::Output;
| ^^^^^^^^^^^^^^^^^^^^^^
|
help: use fully-qualified syntax
|
LL - type H = Fn(u8) -> (u8)::Output;
LL + type H = <(dyn Fn(u8) -> u8 + 'static) as BitOr>::Output;
| ^^^^^^^^^^^^^^
|
LL - type H = Fn(u8) -> (u8)::Output;
LL + type H = <(dyn Fn(u8) -> u8 + 'static) as IntoFuture>::Output;
help: please supply an explicit bound
|
LL | type H = Fn(u8) -> (u8) + /* 'a */::Output;
| ++++++++++

error[E0223]: ambiguous associated type
--> $DIR/bad-assoc-ty.rs:44:19
Expand Down Expand Up @@ -310,5 +306,5 @@ LL | fn foo<F>(_: F) where F: Fn() -> _ {}

error: aborting due to 30 previous errors; 1 warning emitted

Some errors have detailed explanations: E0121, E0223, E0740.
Some errors have detailed explanations: E0121, E0223, E0228, E0740.
For more information about an error, try `rustc --explain E0121`.
4 changes: 2 additions & 2 deletions tests/ui/did_you_mean/bad-assoc-ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ type G = dyn 'static + (Send)::AssocTy;
// This is actually a legal path with fn-like generic arguments in the middle!
// Recovery should not apply in this context.
type H = Fn(u8) -> (u8)::Output;
//[edition2015]~^ ERROR ambiguous associated type
//[edition2021]~^ ERROR expected a type, found a trait
//[edition2015]~^^ ERROR cannot deduce the lifetime bound for this trait object type from context
//[edition2015]~| WARN trait objects without an explicit `dyn` are deprecated
//[edition2015]~| WARN this is accepted in the current edition
//[edition2021]~^^^^ ERROR expected a type, found a trait

macro_rules! ty {
($ty: ty) => ($ty::AssocTy);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Ideally, given an assoc type binding `dyn Trait<AssocTy = Ty>`, we'd factor in the item bounds of
// assoc type `AssocTy` when computing the trait object lifetime default for type `Ty`.
//
// However, since the current implementation can't handle this we instead conservatively and hackily
// treat the trait object lifetime default of the RHS as indeterminate if any lifetime arguments are
// passed to the trait ref (or the GAT) thus rejecting any implicit trait object lifetime bounds.
// This way, we can still implement the desired behavior in the future.

trait Foo<'a> {
type Item: 'a + ?Sized;

fn item(&self) -> Box<Self::Item> { panic!() }
}

trait Bar {}

impl<T> Foo<'_> for T {
type Item = dyn Bar;
}

fn is_static<T>(_: T) where T: 'static {}

// FIXME: Ideally, we'd elaborate `dyn Bar` to `dyn Bar + 'a` instead of rejecting it.
fn bar<'a>(x: &'a str) -> &'a dyn Foo<'a, Item = dyn Bar> { &() }
//~^ ERROR cannot deduce the lifetime bound for this trait object type from context

fn main() {
let s = format!("foo");
let r = bar(&s);

// If it weren't for the conservative path above, we'd expect an error here.
is_static(r.item());
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
error[E0228]: cannot deduce the lifetime bound for this trait object type from context
--> $DIR/object-lifetime-default-assoc-ty-binding-item-bounds-non-static.rs:24:50
|
LL | fn bar<'a>(x: &'a str) -> &'a dyn Foo<'a, Item = dyn Bar> { &() }
| ^^^^^^^
|
help: please supply an explicit bound
|
LL | fn bar<'a>(x: &'a str) -> &'a dyn Foo<'a, Item = dyn Bar + /* 'a */> { &() }
| ++++++++++

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0228`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Ideally, given an assoc type binding `dyn Trait<AssocTy = Ty>`, we'd factor in the item bounds of
// assoc type `AssocTy` when computing the trait object lifetime default for type `Ty`.
//
// However, since the current implementation can't handle this we instead conservatively and hackily
// treat the trait object lifetime default of the RHS as indeterminate if any lifetime arguments are
// passed to the trait ref (or the GAT) thus rejecting any implicit trait object lifetime bounds.
// This way, we can still implement the desired behavior in the future.

trait Foo<'a> {
type Item: ?Sized;

fn item(&self) -> Box<Self::Item> { panic!() }
}

trait Bar {}

impl<T> Foo<'_> for T {
type Item = dyn Bar;
}

fn is_static<T>(_: T) where T: 'static {}

// FIXME: Ideally, we'd elaborate `dyn Bar` to `dyn Bar + 'static` instead of rejecting it.
fn bar<'a>(x: &'a str) -> &'a dyn Foo<'a, Item = dyn Bar> { &() }
//~^ ERROR cannot deduce the lifetime bound for this trait object type from context

// FIXME: Ideally, we'd elaborate `dyn Bar` to `dyn Bar + 'static` instead of rejecting it.
fn baz(x: &str) -> &dyn Foo<Item = dyn Bar> { &() }
//~^ ERROR cannot deduce the lifetime bound for this trait object type from context

fn main() {
let s = format!("foo");
let r = bar(&s);
is_static(r.item());
let r = baz(&s);
is_static(r.item());
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
error[E0228]: cannot deduce the lifetime bound for this trait object type from context
--> $DIR/object-lifetime-default-assoc-ty-binding-item-bounds.rs:24:50
|
LL | fn bar<'a>(x: &'a str) -> &'a dyn Foo<'a, Item = dyn Bar> { &() }
| ^^^^^^^
|
help: please supply an explicit bound
|
LL | fn bar<'a>(x: &'a str) -> &'a dyn Foo<'a, Item = dyn Bar + /* 'a */> { &() }
| ++++++++++

error[E0228]: cannot deduce the lifetime bound for this trait object type from context
--> $DIR/object-lifetime-default-assoc-ty-binding-item-bounds.rs:28:36
|
LL | fn baz(x: &str) -> &dyn Foo<Item = dyn Bar> { &() }
| ^^^^^^^
|
help: please supply an explicit bound
|
LL | fn baz(x: &str) -> &dyn Foo<Item = dyn Bar + /* 'a */> { &() }
| ++++++++++

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0228`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Check that resolved associated type paths induce the correct
// trait object lifetime default for the self type.

//@ check-pass

trait Outer { type Ty; }
trait Inner {}

impl<'a> Outer for dyn Inner + 'a { type Ty = &'a (); }

// We deduce `dyn Inner + 'static` from absence of any bounds on self ty param of trait `Outer`.
//
// Prior to PR rust-lang/rust#129543, assoc tys weren't considered eligible *containers* and
// thus we'd use the *trait object lifetime default* induced by the reference type ctor `&`,
// namely `'r`. Now however, the assoc ty overrides that default to be `'static`.
fn f<'r>(x: &'r <dyn Inner as Outer>::Ty) { /*check*/ g(x) }
fn g<'r>(x: &'r <dyn Inner + 'static as Outer>::Ty) {}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Check that resolved associated type paths induce the correct
// trait object lifetime default for the self type.

//@ check-pass
//@ revisions: bound clause

// RBV works on the HIR where where-clauses and item bounds of traits aren't merged yet.
// It's therefore wise to check both forms and make sure both are treated the same by RBV.
#[cfg(bound)] trait Outer<'a>: 'a { type Ty; }
#[cfg(clause)] trait Outer<'a> where Self: 'a { type Ty; }
trait Inner {}

impl<'a> Outer<'a> for dyn Inner + 'a { type Ty = &'a (); }

fn f<'r>(x: <dyn Inner + 'r as Outer<'r>>::Ty) { /*check*/ g(x) }
// We deduce `dyn Inner + 'r` from bound `'a` on self ty param of trait `Outer`.
fn g<'r>(x: <dyn Inner as Outer<'r>>::Ty) {}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Ideally, given an assoc type binding `dyn Trait<AssocTy = Ty>`, we'd factor in the item bounds of
// assoc type `AssocTy` when computing the trait object lifetime default for type `Ty`.
//
// However, since the current implementation can't handle this we instead conservatively and hackily
// treat the trait object lifetime default of the RHS as indeterminate if any lifetime arguments are
// passed to (the trait ref or) the GAT thus rejecting any implicit trait object lifetime bounds.
// This way, we can still implement the desired behavior in the future.

trait Outer {
type A<'r>: ?Sized;
type B<'r>: ?Sized + 'r;
}

trait Inner {}

// FIXME: Ideally, we'd elaborate `dyn Inner` to `dyn Inner + 'static` here instead of rejecting it.
fn f0<'r>(x: impl Outer<A<'r> = dyn Inner>) { /*check*/ g0(x) }
//~^ ERROR cannot deduce the lifetime bound for this trait object type from context
fn g0<'r>(_: impl Outer<A<'r> = dyn Inner + 'static>) {}

fn f1<'r>(x: impl Outer<B<'r> = dyn Inner + 'r>) { /*check*/ g1(x) }
// FIXME: Ideally, we'd elaborate `dyn Inner` to `dyn Inner + 'r` here instead of rejecting it.
fn g1<'r>(_: impl Outer<B<'r> = dyn Inner>) {}
//~^ ERROR cannot deduce the lifetime bound for this trait object type from context

fn main() {}
Loading
Loading