From dbdd65cc89955eec97a26cc0de4f27970ae7df6c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 21 Feb 2023 17:54:00 +0000 Subject: [PATCH 1/3] Drive-by assertion in collect_return_position_impl_trait_in_trait_tys --- compiler/rustc_hir_analysis/src/check/compare_impl_item.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 50005582f7cec..3409b55327244 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -648,6 +648,13 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( tcx.fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs), ) .fold_with(&mut collector); + + debug_assert_ne!( + collector.types.len(), + 0, + "expect >1 RPITITs in call to `collect_return_position_impl_trait_in_trait_tys`" + ); + let trait_sig = ocx.normalize(&norm_cause, param_env, unnormalized_trait_sig); trait_sig.error_reported()?; let trait_return_ty = trait_sig.output(); From b42a811b0e42ee2be00311bf8732a2c2daa246a2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 21 Feb 2023 18:27:17 +0000 Subject: [PATCH 2/3] Don't project specializable RPITIT projection --- .../src/traits/project.rs | 17 +++++ ...ont-project-to-specializable-projection.rs | 71 +++++++++++++++++++ ...project-to-specializable-projection.stderr | 26 +++++++ 3 files changed, 114 insertions(+) create mode 100644 tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs create mode 100644 tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 279725b16d8a6..c5ed2600e30df 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1307,6 +1307,23 @@ fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>( let _ = selcx.infcx.commit_if_ok(|_| { match selcx.select(&obligation.with(tcx, trait_predicate)) { Ok(Some(super::ImplSource::UserDefined(data))) => { + let Ok(leaf_def) = specialization_graph::assoc_def(tcx, data.impl_def_id, trait_fn_def_id) else { + return Err(()); + }; + // Only reveal a specializable default if we're past type-checking + // and the obligation is monomorphic, otherwise passes such as + // transmute checking and polymorphic MIR optimizations could + // get a result which isn't correct for all monomorphizations. + if !leaf_def.is_final() + && obligation.param_env.reveal() != Reveal::All + && selcx + .infcx + .resolve_vars_if_possible(obligation.predicate.trait_ref(tcx)) + .still_further_specializable() + { + return Err(()); + } + candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(data)); Ok(()) } diff --git a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs new file mode 100644 index 0000000000000..afd3db5e0525e --- /dev/null +++ b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs @@ -0,0 +1,71 @@ +// edition: 2021 +// known-bug: #108309 + +#![feature(async_fn_in_trait)] +#![feature(min_specialization)] + +struct MyStruct; + +trait MyTrait { + async fn foo(_: T) -> &'static str; +} + +impl MyTrait for MyStruct { + default async fn foo(_: T) -> &'static str { + "default" + } +} + +impl MyTrait for MyStruct { + async fn foo(_: i32) -> &'static str { + "specialized" + } +} + +async fn async_main() { + assert_eq!(MyStruct::foo(42).await, "specialized"); + assert_eq!(indirection(42).await, "specialized"); +} + +async fn indirection(x: T) -> &'static str { + //explicit type coercion is currently necessary + // because of https://github.com/rust-lang/rust/issues/67918 + >::foo(x).await +} + +// ------------------------------------------------------------------------- // +// Implementation Details Below... + +use std::future::Future; +use std::pin::Pin; +use std::task::*; + +pub fn noop_waker() -> Waker { + let raw = RawWaker::new(std::ptr::null(), &NOOP_WAKER_VTABLE); + + // SAFETY: the contracts for RawWaker and RawWakerVTable are upheld + unsafe { Waker::from_raw(raw) } +} + +const NOOP_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(noop_clone, noop, noop, noop); + +unsafe fn noop_clone(_p: *const ()) -> RawWaker { + RawWaker::new(std::ptr::null(), &NOOP_WAKER_VTABLE) +} + +unsafe fn noop(_p: *const ()) {} + +fn main() { + let mut fut = async_main(); + + // Poll loop, just to test the future... + let waker = noop_waker(); + let ctx = &mut Context::from_waker(&waker); + + loop { + match unsafe { Pin::new_unchecked(&mut fut).poll(ctx) } { + Poll::Pending => {} + Poll::Ready(()) => break, + } + } +} diff --git a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr new file mode 100644 index 0000000000000..371122ea71ec0 --- /dev/null +++ b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr @@ -0,0 +1,26 @@ +warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/dont-project-to-specializable-projection.rs:4:12 + | +LL | #![feature(async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #91611 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0053]: method `foo` has an incompatible type for trait + --> $DIR/dont-project-to-specializable-projection.rs:14:35 + | +LL | default async fn foo(_: T) -> &'static str { + | ^^^^^^^^^^^^ expected associated type, found future + | +note: type in trait + --> $DIR/dont-project-to-specializable-projection.rs:10:27 + | +LL | async fn foo(_: T) -> &'static str; + | ^^^^^^^^^^^^ + = note: expected signature `fn(_) -> impl Future` + found signature `fn(_) -> impl Future` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0053`. From 7ceaf5214425e5471ca025e1ba1795bc4f5c6261 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 21 Feb 2023 19:59:44 +0000 Subject: [PATCH 3/3] Support specializtion for RPITITs --- .../src/check/compare_impl_item.rs | 28 ++++-- compiler/rustc_metadata/src/rmeta/encoder.rs | 30 +------ compiler/rustc_middle/src/query/mod.rs | 8 ++ compiler/rustc_middle/src/ty/mod.rs | 28 ++++++ compiler/rustc_middle/src/ty/subst.rs | 2 +- .../src/traits/project.rs | 4 +- compiler/rustc_ty_utils/src/ty.rs | 89 +++++++++++++++---- ...ont-project-to-specializable-projection.rs | 3 +- ...project-to-specializable-projection.stderr | 17 +--- .../in-trait/method-signature-matches.rs | 4 +- .../in-trait/method-signature-matches.stderr | 37 +++++--- .../in-trait/specialization-broken.rs | 4 +- .../in-trait/specialization-broken.stderr | 23 ----- 13 files changed, 163 insertions(+), 114 deletions(-) delete mode 100644 tests/ui/impl-trait/in-trait/specialization-broken.stderr diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 3409b55327244..bf2ad1861901d 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -50,7 +50,7 @@ pub(super) fn compare_impl_method<'tcx>( compare_generic_param_kinds(tcx, impl_m, trait_m, false)?; compare_number_of_method_arguments(tcx, impl_m, trait_m)?; compare_synthetic_generics(tcx, impl_m, trait_m)?; - compare_asyncness(tcx, impl_m, trait_m)?; + compare_asyncness(tcx, impl_m, trait_m, false)?; compare_method_predicate_entailment( tcx, impl_m, @@ -191,6 +191,11 @@ fn compare_method_predicate_entailment<'tcx>( .map(|(predicate, _)| predicate), ); + // Additionally, we are allowed to assume that we can project RPITITs to their + // associated hidden types within method signatures. This is to allow us to support + // specialization with `impl Trait` in traits. + hybrid_preds.predicates.extend(tcx.additional_method_assumptions(impl_m_def_id)); + // Construct trait parameter environment and then shift it into the placeholder viewpoint. // The key step here is to update the caller_bounds's predicates to be // the new hybrid bounds we computed. @@ -526,6 +531,7 @@ fn compare_asyncness<'tcx>( tcx: TyCtxt<'tcx>, impl_m: ty::AssocItem, trait_m: ty::AssocItem, + delay: bool, ) -> Result<(), ErrorGuaranteed> { if tcx.asyncness(trait_m.def_id) == hir::IsAsync::Async { match tcx.fn_sig(impl_m.def_id).skip_binder().skip_binder().output().kind() { @@ -536,11 +542,14 @@ fn compare_asyncness<'tcx>( // We don't know if it's ok, but at least it's already an error. } _ => { - return Err(tcx.sess.emit_err(crate::errors::AsyncTraitImplShouldBeAsync { - span: tcx.def_span(impl_m.def_id), - method_name: trait_m.name, - trait_item_span: tcx.hir().span_if_local(trait_m.def_id), - })); + return Err(tcx + .sess + .create_err(crate::errors::AsyncTraitImplShouldBeAsync { + span: tcx.def_span(impl_m.def_id), + method_name: trait_m.name, + trait_item_span: tcx.hir().span_if_local(trait_m.def_id), + }) + .emit_unless(delay)); } }; } @@ -590,10 +599,15 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap(); let impl_trait_ref = tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap().subst_identity(); - let param_env = tcx.param_env(def_id); + + // We use the RPITIT values computed in this method to construct the param-env, + // so to avoid cycles, we do computations in this function without assuming anything + // about RPITIT projection. + let param_env = tcx.param_env_no_assumptions(def_id); // First, check a few of the same things as `compare_impl_method`, // just so we don't ICE during substitution later. + compare_asyncness(tcx, impl_m, trait_m, true)?; compare_number_of_generics(tcx, impl_m, trait_m, true)?; compare_generic_param_kinds(tcx, impl_m, trait_m, true)?; check_region_bounds_on_impl_item(tcx, impl_m, trait_m, true)?; diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index f0dafe73c004e..27490a09a3646 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1101,34 +1101,6 @@ fn should_encode_const(def_kind: DefKind) -> bool { } } -fn should_encode_trait_impl_trait_tys(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - if tcx.def_kind(def_id) != DefKind::AssocFn { - return false; - } - - let Some(item) = tcx.opt_associated_item(def_id) else { return false; }; - if item.container != ty::AssocItemContainer::ImplContainer { - return false; - } - - let Some(trait_item_def_id) = item.trait_item_def_id else { return false; }; - - // FIXME(RPITIT): This does a somewhat manual walk through the signature - // of the trait fn to look for any RPITITs, but that's kinda doing a lot - // of work. We can probably remove this when we refactor RPITITs to be - // associated types. - tcx.fn_sig(trait_item_def_id).subst_identity().skip_binder().output().walk().any(|arg| { - if let ty::GenericArgKind::Type(ty) = arg.unpack() - && let ty::Alias(ty::Projection, data) = ty.kind() - && tcx.def_kind(data.def_id) == DefKind::ImplTraitPlaceholder - { - true - } else { - false - } - }) -} - // Return `false` to avoid encoding impl trait in trait, while we don't use the query. fn should_encode_fn_impl_trait_in_trait<'tcx>(_tcx: TyCtxt<'tcx>, _def_id: DefId) -> bool { false @@ -1211,7 +1183,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if let DefKind::Enum | DefKind::Struct | DefKind::Union = def_kind { self.encode_info_for_adt(def_id); } - if should_encode_trait_impl_trait_tys(tcx, def_id) + if tcx.impl_method_has_trait_impl_trait_tys(def_id) && let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id) { record!(self.tables.trait_impl_trait_tys[def_id] <- table); diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 6a34e5ede1938..f924d1529028c 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1313,6 +1313,14 @@ rustc_queries! { desc { |tcx| "computing normalized predicates of `{}`", tcx.def_path_str(def_id) } } + query param_env_no_assumptions(def_id: DefId) -> ty::ParamEnv<'tcx> { + desc { |tcx| "computing normalized predicates of `{}`", tcx.def_path_str(def_id) } + } + + query additional_method_assumptions(def_id: DefId) -> &'tcx ty::List> { + desc { |tcx| "computing additional predicate assumptions for the body of `{}`", tcx.def_path_str(def_id) } + } + /// Like `param_env`, but returns the `ParamEnv` in `Reveal::All` mode. /// Prefer this over `tcx.param_env(def_id).with_reveal_all_normalized(tcx)`, /// as this method is more efficient. diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 7dcc3ff4e7b33..c23d5550900b7 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2544,6 +2544,34 @@ impl<'tcx> TyCtxt<'tcx> { } def_id } + + pub fn impl_method_has_trait_impl_trait_tys(self, def_id: DefId) -> bool { + if self.def_kind(def_id) != DefKind::AssocFn { + return false; + } + + let Some(item) = self.opt_associated_item(def_id) else { return false; }; + if item.container != ty::AssocItemContainer::ImplContainer { + return false; + } + + let Some(trait_item_def_id) = item.trait_item_def_id else { return false; }; + + // FIXME(RPITIT): This does a somewhat manual walk through the signature + // of the trait fn to look for any RPITITs, but that's kinda doing a lot + // of work. We can probably remove this when we refactor RPITITs to be + // associated types. + self.fn_sig(trait_item_def_id).subst_identity().skip_binder().output().walk().any(|arg| { + if let ty::GenericArgKind::Type(ty) = arg.unpack() + && let ty::Alias(ty::Projection, data) = ty.kind() + && self.def_kind(data.def_id) == DefKind::ImplTraitPlaceholder + { + true + } else { + false + } + }) + } } /// Yields the parent function's `LocalDefId` if `def_id` is an `impl Trait` definition. diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 1ed3ef5745b6f..8a8df3adefef0 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -468,7 +468,7 @@ impl<'tcx> InternalSubsts<'tcx> { target_substs: SubstsRef<'tcx>, ) -> SubstsRef<'tcx> { let defs = tcx.generics_of(source_ancestor); - tcx.mk_substs(target_substs.iter().chain(self.iter().skip(defs.params.len()))) + tcx.mk_substs(target_substs.iter().chain(self.iter().skip(defs.count()))) } pub fn truncate_to(&self, tcx: TyCtxt<'tcx>, generics: &ty::Generics) -> SubstsRef<'tcx> { diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index c5ed2600e30df..cb62746452608 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1246,13 +1246,13 @@ fn project<'cx, 'tcx>( let mut candidates = ProjectionCandidateSet::None; - assemble_candidate_for_impl_trait_in_trait(selcx, obligation, &mut candidates); - // Make sure that the following procedures are kept in order. ParamEnv // needs to be first because it has highest priority, and Select checks // the return value of push_candidate which assumes it's ran at last. assemble_candidates_from_param_env(selcx, obligation, &mut candidates); + assemble_candidate_for_impl_trait_in_trait(selcx, obligation, &mut candidates); + assemble_candidates_from_trait_def(selcx, obligation, &mut candidates); assemble_candidates_from_object_ty(selcx, obligation, &mut candidates); diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index a47e7ce23e3c0..bf665da92e2f2 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -116,7 +116,7 @@ fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> &[Ty<'_>] { } /// See `ParamEnv` struct definition for details. -fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { +fn param_env(tcx: TyCtxt<'_>, def_id: DefId, add_assumptions: bool) -> ty::ParamEnv<'_> { // Compute the bounds on Self and the type parameters. let ty::InstantiatedPredicates { mut predicates, .. } = tcx.predicates_of(def_id).instantiate_identity(tcx); @@ -138,17 +138,8 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { predicates.extend(environment); } - if tcx.def_kind(def_id) == DefKind::AssocFn - && tcx.associated_item(def_id).container == ty::AssocItemContainer::TraitContainer - { - let sig = tcx.fn_sig(def_id).subst_identity(); - sig.visit_with(&mut ImplTraitInTraitFinder { - tcx, - fn_def_id: def_id, - bound_vars: sig.bound_vars(), - predicates: &mut predicates, - seen: FxHashSet::default(), - }); + if add_assumptions && tcx.def_kind(def_id) == DefKind::AssocFn { + predicates.extend(tcx.additional_method_assumptions(def_id)) } let local_did = def_id.as_local(); @@ -237,19 +228,83 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { traits::normalize_param_env_or_error(tcx, unnormalized_env, cause) } +fn additional_method_assumptions<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, +) -> &'tcx ty::List> { + let assoc_item = tcx.associated_item(def_id); + let mut predicates = vec![]; + + match assoc_item.container { + ty::AssocItemContainer::TraitContainer => { + let sig = tcx.fn_sig(def_id).subst_identity(); + sig.visit_with(&mut ImplTraitInTraitFinder { + tcx, + fn_def_id: def_id, + bound_vars: sig.bound_vars(), + predicates: &mut predicates, + seen: FxHashSet::default(), + hidden_ty: |alias_ty| tcx.mk_alias(ty::Opaque, alias_ty), + }); + } + ty::AssocItemContainer::ImplContainer => { + if tcx.impl_method_has_trait_impl_trait_tys(def_id) + && let Ok(table) + = tcx.collect_return_position_impl_trait_in_trait_tys(def_id) + { + let impl_def_id = assoc_item.container_id(tcx); + let trait_to_impl_substs = + tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity().substs; + // Create mapping from impl to placeholder. + let impl_to_placeholder_substs = ty::InternalSubsts::identity_for_item(tcx, def_id); + // Create mapping from trait to placeholder. + let trait_to_placeholder_substs = + impl_to_placeholder_substs.rebase_onto(tcx, impl_def_id, trait_to_impl_substs); + + let trait_fn_def_id = assoc_item.trait_item_def_id.unwrap(); + let trait_fn_sig = + tcx.fn_sig(trait_fn_def_id).subst(tcx, trait_to_placeholder_substs); + trait_fn_sig.visit_with(&mut ImplTraitInTraitFinder { + tcx, + fn_def_id: trait_fn_def_id, + bound_vars: trait_fn_sig.bound_vars(), + predicates: &mut predicates, + seen: FxHashSet::default(), + hidden_ty: |alias_ty| { + EarlyBinder(*table.get(&alias_ty.def_id).unwrap()).subst( + tcx, + alias_ty.substs.rebase_onto( + tcx, + trait_fn_def_id, + impl_to_placeholder_substs, + ), + ) + }, + }); + } + } + } + + tcx.intern_predicates(&predicates) +} + /// Walk through a function type, gathering all RPITITs and installing a /// `NormalizesTo(Projection(RPITIT) -> Opaque(RPITIT))` predicate into the /// predicates list. This allows us to observe that an RPITIT projects to /// its corresponding opaque within the body of a default-body trait method. -struct ImplTraitInTraitFinder<'a, 'tcx> { +struct ImplTraitInTraitFinder<'a, 'tcx, F: Fn(ty::AliasTy<'tcx>) -> Ty<'tcx>> { tcx: TyCtxt<'tcx>, predicates: &'a mut Vec>, fn_def_id: DefId, bound_vars: &'tcx ty::List, seen: FxHashSet, + hidden_ty: F, } -impl<'tcx> TypeVisitor> for ImplTraitInTraitFinder<'_, 'tcx> { +impl<'tcx, F> TypeVisitor> for ImplTraitInTraitFinder<'_, 'tcx, F> +where + F: Fn(ty::AliasTy<'tcx>) -> Ty<'tcx>, +{ fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow { if let ty::Alias(ty::Projection, alias_ty) = *ty.kind() && self.tcx.def_kind(alias_ty.def_id) == DefKind::ImplTraitPlaceholder @@ -260,7 +315,7 @@ impl<'tcx> TypeVisitor> for ImplTraitInTraitFinder<'_, 'tcx> { ty::Binder::bind_with_vars( ty::ProjectionPredicate { projection_ty: alias_ty, - term: self.tcx.mk_alias(ty::Opaque, alias_ty).into(), + term: (self.hidden_ty)(alias_ty).into(), }, self.bound_vars, ) @@ -514,7 +569,9 @@ pub fn provide(providers: &mut ty::query::Providers) { *providers = ty::query::Providers { asyncness, adt_sized_constraint, - param_env, + param_env: |tcx, def_id| param_env(tcx, def_id, true), + param_env_no_assumptions: |tcx, def_id| param_env(tcx, def_id, false), + additional_method_assumptions, param_env_reveal_all_normalized, instance_def_size_estimate, issue33140_self_ty, diff --git a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs index afd3db5e0525e..113de64a38b5d 100644 --- a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs +++ b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs @@ -1,7 +1,8 @@ // edition: 2021 -// known-bug: #108309 +// check-pass #![feature(async_fn_in_trait)] +//~^ WARN the feature `async_fn_in_trait` is incomplete #![feature(min_specialization)] struct MyStruct; diff --git a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr index 371122ea71ec0..7b23a868ded87 100644 --- a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr +++ b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr @@ -7,20 +7,5 @@ LL | #![feature(async_fn_in_trait)] = note: see issue #91611 for more information = note: `#[warn(incomplete_features)]` on by default -error[E0053]: method `foo` has an incompatible type for trait - --> $DIR/dont-project-to-specializable-projection.rs:14:35 - | -LL | default async fn foo(_: T) -> &'static str { - | ^^^^^^^^^^^^ expected associated type, found future - | -note: type in trait - --> $DIR/dont-project-to-specializable-projection.rs:10:27 - | -LL | async fn foo(_: T) -> &'static str; - | ^^^^^^^^^^^^ - = note: expected signature `fn(_) -> impl Future` - found signature `fn(_) -> impl Future` - -error: aborting due to previous error; 1 warning emitted +warning: 1 warning emitted -For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.rs b/tests/ui/impl-trait/in-trait/method-signature-matches.rs index c848ee3f643de..bf5a2d0f2e407 100644 --- a/tests/ui/impl-trait/in-trait/method-signature-matches.rs +++ b/tests/ui/impl-trait/in-trait/method-signature-matches.rs @@ -27,7 +27,7 @@ trait TooMuch { impl TooMuch for () { fn calm_down_please(_: (), _: (), _: ()) {} - //~^ ERROR method `calm_down_please` has 3 parameters but the declaration in trait `TooMuch::calm_down_please` has 0 + //~^ ERROR method `calm_down_please` has an incompatible type for trait } trait TooLittle { @@ -36,7 +36,7 @@ trait TooLittle { impl TooLittle for () { fn come_on_a_little_more_effort() {} - //~^ ERROR method `come_on_a_little_more_effort` has 0 parameters but the declaration in trait `TooLittle::come_on_a_little_more_effort` has 3 + //~^ ERROR method `come_on_a_little_more_effort` has an incompatible type for trait } trait Lifetimes { diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.stderr b/tests/ui/impl-trait/in-trait/method-signature-matches.stderr index 3ec62020e6c89..0a1d0a5e44067 100644 --- a/tests/ui/impl-trait/in-trait/method-signature-matches.stderr +++ b/tests/ui/impl-trait/in-trait/method-signature-matches.stderr @@ -32,23 +32,33 @@ LL | async fn owo(x: ()) {} = note: expected signature `fn(()) -> _` found signature `fn(u8) -> _` -error[E0050]: method `calm_down_please` has 3 parameters but the declaration in trait `TooMuch::calm_down_please` has 0 - --> $DIR/method-signature-matches.rs:29:28 +error[E0053]: method `calm_down_please` has an incompatible type for trait + --> $DIR/method-signature-matches.rs:29:46 | -LL | fn calm_down_please() -> impl Sized; - | ------------------------------------ trait requires 0 parameters -... LL | fn calm_down_please(_: (), _: (), _: ()) {} - | ^^^^^^^^^^^^^^^^ expected 0 parameters, found 3 + | ^ incorrect number of function parameters + | +note: type in trait + --> $DIR/method-signature-matches.rs:25:5 + | +LL | fn calm_down_please() -> impl Sized; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: expected signature `fn()` + found signature `fn((), (), ())` -error[E0050]: method `come_on_a_little_more_effort` has 0 parameters but the declaration in trait `TooLittle::come_on_a_little_more_effort` has 3 - --> $DIR/method-signature-matches.rs:38:5 +error[E0053]: method `come_on_a_little_more_effort` has an incompatible type for trait + --> $DIR/method-signature-matches.rs:38:39 | -LL | fn come_on_a_little_more_effort(_: (), _: (), _: ()) -> impl Sized; - | ---------------- trait requires 3 parameters -... LL | fn come_on_a_little_more_effort() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 3 parameters, found 0 + | ^ incorrect number of function parameters + | +note: type in trait + --> $DIR/method-signature-matches.rs:34:5 + | +LL | fn come_on_a_little_more_effort(_: (), _: (), _: ()) -> impl Sized; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: expected signature `fn((), (), ())` + found signature `fn()` error[E0053]: method `early` has an incompatible type for trait --> $DIR/method-signature-matches.rs:47:27 @@ -70,5 +80,4 @@ LL | fn early<'early, T>(x: &'early T) -> impl Sized; error: aborting due to 5 previous errors -Some errors have detailed explanations: E0050, E0053. -For more information about an error, try `rustc --explain E0050`. +For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/impl-trait/in-trait/specialization-broken.rs b/tests/ui/impl-trait/in-trait/specialization-broken.rs index 9d27d3710a601..ac2b3eb0d55fc 100644 --- a/tests/ui/impl-trait/in-trait/specialization-broken.rs +++ b/tests/ui/impl-trait/in-trait/specialization-broken.rs @@ -1,5 +1,4 @@ -// FIXME(compiler-errors): I'm not exactly sure if this is expected to pass or not. -// But we fixed an ICE anyways. +// check-pass #![feature(specialization)] #![feature(return_position_impl_trait_in_trait)] @@ -14,7 +13,6 @@ where U: Copy, { fn bar(&self) -> U { - //~^ ERROR method `bar` has an incompatible type for trait *self } } diff --git a/tests/ui/impl-trait/in-trait/specialization-broken.stderr b/tests/ui/impl-trait/in-trait/specialization-broken.stderr deleted file mode 100644 index 37cfd74498d81..0000000000000 --- a/tests/ui/impl-trait/in-trait/specialization-broken.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error[E0053]: method `bar` has an incompatible type for trait - --> $DIR/specialization-broken.rs:16:22 - | -LL | default impl Foo for U - | - this type parameter -... -LL | fn bar(&self) -> U { - | ^ - | | - | expected associated type, found type parameter `U` - | help: change the output type to match the trait: `impl Sized` - | -note: type in trait - --> $DIR/specialization-broken.rs:9:22 - | -LL | fn bar(&self) -> impl Sized; - | ^^^^^^^^^^ - = note: expected signature `fn(&U) -> impl Sized` - found signature `fn(&U) -> U` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0053`.