diff options
| author | bors <bors@rust-lang.org> | 2023-05-10 07:39:31 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-05-10 07:39:31 +0000 |
| commit | 7a41eacf170ed234e059608515115e94fbe721fe (patch) | |
| tree | bba0f53fa3cae672594193a410b19c864c12cc5f /compiler/rustc_hir_analysis/src | |
| parent | 7fb4332ce452875b0f86dd62be0b1356e6d9537d (diff) | |
| parent | 68c7d2083f315a349caf3202a5495b1c99a38461 (diff) | |
| download | rust-7a41eacf170ed234e059608515115e94fbe721fe.tar.gz rust-7a41eacf170ed234e059608515115e94fbe721fe.zip | |
Auto merge of #2885 - RalfJung:rustup, r=RalfJung
Rustup
Diffstat (limited to 'compiler/rustc_hir_analysis/src')
11 files changed, 146 insertions, 70 deletions
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 5ee0cf94360..6ac1df6a079 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -2419,6 +2419,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { return Ok(None); } + // + // Select applicable inherent associated type candidates modulo regions. + // + // In contexts that have no inference context, just make a new one. // We do need a local variable to store it, though. let infcx_; @@ -2431,7 +2435,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } }; - let param_env = tcx.param_env(block.owner.to_def_id()); + // FIXME(inherent_associated_types): Acquiring the ParamEnv this early leads to cycle errors + // when inside of an ADT (#108491) or where clause. + let param_env = tcx.param_env(block.owner); let cause = ObligationCause::misc(span, block.owner.def_id); let mut fulfillment_errors = Vec::new(); @@ -2439,6 +2445,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let universe = infcx.create_next_universe(); // Regions are not considered during selection. + // FIXME(non_lifetime_binders): Here we are "truncating" or "flattening" the universes + // of type and const binders. Is that correct in the selection phase? See also #109505. let self_ty = tcx.replace_escaping_bound_vars_uncached( self_ty, FnMutDelegate { @@ -2454,41 +2462,40 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { candidates .iter() - .filter_map(|&(impl_, (assoc_item, def_scope))| { + .copied() + .filter(|&(impl_, _)| { infcx.probe(|_| { let ocx = ObligationCtxt::new_in_snapshot(&infcx); - let impl_ty = tcx.type_of(impl_); let impl_substs = infcx.fresh_item_substs(impl_); - let impl_ty = impl_ty.subst(tcx, impl_substs); + let impl_ty = tcx.type_of(impl_).subst(tcx, impl_substs); let impl_ty = ocx.normalize(&cause, param_env, impl_ty); - // Check that the Self-types can be related. - // FIXME(fmease): Should we use `eq` here? - ocx.sup(&ObligationCause::dummy(), param_env, impl_ty, self_ty).ok()?; + // Check that the self types can be related. + // FIXME(inherent_associated_types): Should we use `eq` here? Method probing uses + // `sup` for this situtation, too. What for? To constrain inference variables? + if ocx.sup(&ObligationCause::dummy(), param_env, impl_ty, self_ty).is_err() + { + return false; + } // Check whether the impl imposes obligations we have to worry about. - let impl_bounds = tcx.predicates_of(impl_); - let impl_bounds = impl_bounds.instantiate(tcx, impl_substs); - + let impl_bounds = tcx.predicates_of(impl_).instantiate(tcx, impl_substs); let impl_bounds = ocx.normalize(&cause, param_env, impl_bounds); - let impl_obligations = traits::predicates_for_generics( |_, _| cause.clone(), param_env, impl_bounds, ); - ocx.register_obligations(impl_obligations); let mut errors = ocx.select_where_possible(); if !errors.is_empty() { fulfillment_errors.append(&mut errors); - return None; + return false; } - // FIXME(fmease): Unsolved vars can escape this InferCtxt snapshot. - Some((assoc_item, def_scope, infcx.resolve_vars_if_possible(impl_substs))) + true }) }) .collect() @@ -2497,24 +2504,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if applicable_candidates.len() > 1 { return Err(self.complain_about_ambiguous_inherent_assoc_type( name, - applicable_candidates.into_iter().map(|(candidate, ..)| candidate).collect(), + applicable_candidates.into_iter().map(|(_, (candidate, _))| candidate).collect(), span, )); } - if let Some((assoc_item, def_scope, impl_substs)) = applicable_candidates.pop() { + if let Some((impl_, (assoc_item, def_scope))) = applicable_candidates.pop() { self.check_assoc_ty(assoc_item, name, def_scope, block, span); - // FIXME(inherent_associated_types): To fully *confirm* the *probed* candidate, we still - // need to relate the Self-type with fresh item substs & register region obligations for - // regionck to prove/disprove. - - let item_substs = - self.create_substs_for_associated_item(span, assoc_item, segment, impl_substs); + // FIXME(fmease): Currently creating throwaway `parent_substs` to please + // `create_substs_for_associated_item`. Modify the latter instead (or sth. similar) to + // not require the parent substs logic. + let parent_substs = InternalSubsts::identity_for_item(tcx, impl_); + let substs = + self.create_substs_for_associated_item(span, assoc_item, segment, parent_substs); + let substs = tcx.mk_substs_from_iter( + std::iter::once(ty::GenericArg::from(self_ty)) + .chain(substs.into_iter().skip(parent_substs.len())), + ); - // FIXME(fmease, #106722): Check if the bounds on the parameters of the - // associated type hold, if any. - let ty = tcx.type_of(assoc_item).subst(tcx, item_substs); + let ty = tcx.mk_alias(ty::Inherent, tcx.mk_alias_ty(assoc_item, substs)); return Ok(Some((ty, assoc_item))); } 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 7384eb25f2e..8bf1e0e84a4 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -60,19 +60,21 @@ pub(super) fn compare_impl_method<'tcx>( }; } -/// This function is best explained by example. Consider a trait: +/// This function is best explained by example. Consider a trait with it's implementation: /// -/// trait Trait<'t, T> { -/// // `trait_m` -/// fn method<'a, M>(t: &'t T, m: &'a M) -> Self; -/// } +/// ```rust +/// trait Trait<'t, T> { +/// // `trait_m` +/// fn method<'a, M>(t: &'t T, m: &'a M) -> Self; +/// } /// -/// And an impl: +/// struct Foo; /// -/// impl<'i, 'j, U> Trait<'j, &'i U> for Foo { -/// // `impl_m` -/// fn method<'b, N>(t: &'j &'i U, m: &'b N) -> Foo; -/// } +/// impl<'i, 'j, U> Trait<'j, &'i U> for Foo { +/// // `impl_m` +/// fn method<'b, N>(t: &'j &'i U, m: &'b N) -> Foo { Foo } +/// } +/// ``` /// /// We wish to decide if those two method types are compatible. /// For this we have to show that, assuming the bounds of the impl hold, the @@ -82,7 +84,9 @@ pub(super) fn compare_impl_method<'tcx>( /// type parameters to impl type parameters. This is taken from the /// impl trait reference: /// -/// trait_to_impl_substs = {'t => 'j, T => &'i U, Self => Foo} +/// ```rust,ignore (pseudo-Rust) +/// trait_to_impl_substs = {'t => 'j, T => &'i U, Self => Foo} +/// ``` /// /// We create a mapping `dummy_substs` that maps from the impl type /// parameters to fresh types and regions. For type parameters, @@ -91,13 +95,17 @@ pub(super) fn compare_impl_method<'tcx>( /// regions (Note: but only early-bound regions, i.e., those /// declared on the impl or used in type parameter bounds). /// -/// impl_to_placeholder_substs = {'i => 'i0, U => U0, N => N0 } +/// ```rust,ignore (pseudo-Rust) +/// impl_to_placeholder_substs = {'i => 'i0, U => U0, N => N0 } +/// ``` /// /// Now we can apply `placeholder_substs` to the type of the impl method /// to yield a new function type in terms of our fresh, placeholder /// types: /// -/// <'b> fn(t: &'i0 U0, m: &'b) -> Foo +/// ```rust,ignore (pseudo-Rust) +/// <'b> fn(t: &'i0 U0, m: &'b) -> Foo +/// ``` /// /// We now want to extract and substitute the type of the *trait* /// method and compare it. To do so, we must create a compound @@ -106,11 +114,15 @@ pub(super) fn compare_impl_method<'tcx>( /// type parameters. We extend the mapping to also include /// the method parameters. /// -/// trait_to_placeholder_substs = { T => &'i0 U0, Self => Foo, M => N0 } +/// ```rust,ignore (pseudo-Rust) +/// trait_to_placeholder_substs = { T => &'i0 U0, Self => Foo, M => N0 } +/// ``` /// /// Applying this to the trait method type yields: /// -/// <'a> fn(t: &'i0 U0, m: &'a) -> Foo +/// ```rust,ignore (pseudo-Rust) +/// <'a> fn(t: &'i0 U0, m: &'a) -> Foo +/// ``` /// /// This type is also the same but the name of the bound region (`'a` /// vs `'b`). However, the normal subtyping rules on fn types handle @@ -1163,7 +1175,7 @@ fn compare_self_type<'tcx>( /// as the number of generics on the respective assoc item in the trait definition. /// /// For example this code emits the errors in the following code: -/// ``` +/// ```rust,compile_fail /// trait Trait { /// fn foo(); /// type Assoc<T>; @@ -1547,7 +1559,7 @@ fn compare_synthetic_generics<'tcx>( /// the same kind as the respective generic parameter in the trait def. /// /// For example all 4 errors in the following code are emitted here: -/// ``` +/// ```rust,ignore (pseudo-Rust) /// trait Foo { /// fn foo<const N: u8>(); /// type bar<const N: u8>; diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 5ce8a83aad7..272177dfbd0 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -210,6 +210,19 @@ fn do_orphan_check_impl<'tcx>( NonlocalImpl::DisallowOther, ), + // ``` + // struct S<T>(T); + // impl<T: ?Sized> S<T> { + // type This = T; + // } + // impl<T: ?Sized> AutoTrait for S<T>::This {} + // ``` + // FIXME(inherent_associated_types): The example code above currently leads to a cycle + ty::Alias(AliasKind::Inherent, _) => ( + LocalImpl::Disallow { problematic_kind: "associated type" }, + NonlocalImpl::DisallowOther, + ), + // type Opaque = impl Trait; // impl AutoTrait for Opaque {} ty::Alias(AliasKind::Opaque, _) => ( diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 119933697a1..ab2932bf969 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -51,7 +51,15 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed. None } else if tcx.lazy_normalization() { - if let Some(param_id) = tcx.hir().opt_const_param_default_param_def_id(hir_id) { + let parent_node = tcx.hir().get_parent(hir_id); + if let Node::Variant(Variant { disr_expr: Some(constant), .. }) = parent_node + && constant.hir_id == hir_id + { + // enum variant discriminants are not allowed to use any kind of generics + None + } else if let Some(param_id) = + tcx.hir().opt_const_param_default_param_def_id(hir_id) + { // If the def_id we are calling generics_of on is an anon ct default i.e: // // struct Foo<const N: usize = { .. }>; @@ -94,15 +102,15 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { has_self: generics.has_self, has_late_bound_regions: generics.has_late_bound_regions, }; + } else { + // HACK(eddyb) this provides the correct generics when + // `feature(generic_const_expressions)` is enabled, so that const expressions + // used with const generics, e.g. `Foo<{N+1}>`, can work at all. + // + // Note that we do not supply the parent generics when using + // `min_const_generics`. + Some(parent_def_id.to_def_id()) } - - // HACK(eddyb) this provides the correct generics when - // `feature(generic_const_expressions)` is enabled, so that const expressions - // used with const generics, e.g. `Foo<{N+1}>`, can work at all. - // - // Note that we do not supply the parent generics when using - // `min_const_generics`. - Some(parent_def_id.to_def_id()) } else { let parent_node = tcx.hir().get_parent(hir_id); match parent_node { @@ -115,11 +123,6 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { { Some(parent_def_id.to_def_id()) } - Node::Variant(Variant { disr_expr: Some(constant), .. }) - if constant.hir_id == hir_id => - { - Some(parent_def_id.to_def_id()) - } Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => { Some(tcx.typeck_root_def_id(def_id.to_def_id())) } diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 6c06957d1ee..e04658c8e77 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -657,14 +657,15 @@ pub(super) fn implied_predicates_with_filter( &*tcx.arena.alloc_from_iter(superbounds.predicates().chain(where_bounds_that_match)); debug!(?implied_bounds); - // Now require that immediate supertraits are converted, - // which will, in turn, reach indirect supertraits. + // Now require that immediate supertraits are converted, which will, in + // turn, reach indirect supertraits, so we detect cycles now instead of + // overflowing during elaboration. if matches!(filter, PredicateFilter::SelfOnly) { - // Now require that immediate supertraits are converted, - // which will, in turn, reach indirect supertraits. for &(pred, span) in implied_bounds { debug!("superbound: {:?}", pred); - if let ty::PredicateKind::Clause(ty::Clause::Trait(bound)) = pred.kind().skip_binder() { + if let ty::PredicateKind::Clause(ty::Clause::Trait(bound)) = pred.kind().skip_binder() + && bound.polarity == ty::ImplPolarity::Positive + { tcx.at(span).super_predicates_of(bound.def_id()); } } 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 ab0dd01ce3a..5c7f7f10b17 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1923,7 +1923,7 @@ fn is_late_bound_map( /// handles cycle detection as we go through the query system. /// /// This is necessary in the first place for the following case: - /// ``` + /// ```rust,ignore (pseudo-Rust) /// type Alias<'a, T> = <T as Trait<'a>>::Assoc; /// fn foo<'a>(_: Alias<'a, ()>) -> Alias<'a, ()> { ... } /// ``` @@ -1948,7 +1948,7 @@ fn is_late_bound_map( ty::Param(param_ty) => { self.arg_is_constrained[param_ty.index as usize] = true; } - ty::Alias(ty::Projection, _) => return ControlFlow::Continue(()), + ty::Alias(ty::Projection | ty::Inherent, _) => return ControlFlow::Continue(()), _ => (), } t.super_visit_with(self) diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index c20fbfd1e40..8df0166f76b 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -127,7 +127,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { // the def_id that this query was called with. We filter to only type and const args here // as a precaution for if it's ever allowed to elide lifetimes in GAT's. It currently isn't // but it can't hurt to be safe ^^ - if let ty::Alias(ty::Projection, projection) = ty.kind() { + if let ty::Alias(ty::Projection | ty::Inherent, projection) = ty.kind() { let generics = tcx.generics_of(projection.def_id); let arg_index = segment diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs index e18b0f08279..9200c2aecf5 100644 --- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs +++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs @@ -59,7 +59,7 @@ struct ParameterCollector { impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ParameterCollector { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { match *t.kind() { - ty::Alias(ty::Projection, ..) if !self.include_nonconstraining => { + ty::Alias(ty::Projection | ty::Inherent, ..) if !self.include_nonconstraining => { // projections are not injective return ControlFlow::Continue(()); } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 379a88538a9..6e7eb4f6cdc 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -815,6 +815,15 @@ pub(crate) struct ClosureImplicitHrtb { } #[derive(Diagnostic)] +#[diag(hir_analysis_empty_specialization)] +pub(crate) struct EmptySpecialization { + #[primary_span] + pub span: Span, + #[note] + pub base_impl_span: Span, +} + +#[derive(Diagnostic)] #[diag(hir_analysis_const_specialize)] pub(crate) struct ConstSpecialize { #[primary_span] diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 5cca2dacb5c..e84da2519ae 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -80,7 +80,7 @@ use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_span::Span; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; -use rustc_trait_selection::traits::{self, translate_substs, wf, ObligationCtxt}; +use rustc_trait_selection::traits::{self, translate_substs_with_cause, wf, ObligationCtxt}; pub(super) fn check_min_specialization(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) { if let Some(node) = parent_specialization_node(tcx, impl_def_id) { @@ -100,12 +100,19 @@ fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId) -> Opti // Implementing a normal trait isn't a specialization. return None; } + if trait_def.is_marker { + // Overlapping marker implementations are not really specializations. + return None; + } Some(impl2_node) } /// Check that `impl1` is a sound specialization #[instrument(level = "debug", skip(tcx))] fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node) { + let span = tcx.def_span(impl1_def_id); + check_has_items(tcx, impl1_def_id, impl2_node, span); + if let Some((impl1_substs, impl2_substs)) = get_impl_substs(tcx, impl1_def_id, impl2_node) { let impl2_def_id = impl2_node.def_id(); debug!(?impl2_def_id, ?impl2_substs); @@ -116,7 +123,6 @@ fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node unconstrained_parent_impl_substs(tcx, impl2_def_id, impl2_substs) }; - let span = tcx.def_span(impl1_def_id); check_constness(tcx, impl1_def_id, impl2_node, span); check_static_lifetimes(tcx, &parent_substs, span); check_duplicate_params(tcx, impl1_substs, &parent_substs, span); @@ -124,6 +130,13 @@ fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node } } +fn check_has_items(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, span: Span) { + if let Node::Impl(impl2_id) = impl2_node && tcx.associated_item_def_ids(impl1_def_id).is_empty() { + let base_impl_span = tcx.def_span(impl2_id); + tcx.sess.emit_err(errors::EmptySpecialization { span, base_impl_span }); + } +} + /// Check that the specializing impl `impl1` is at least as const as the base /// impl `impl2` fn check_constness(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, span: Span) { @@ -167,8 +180,21 @@ fn get_impl_substs( ocx.assumed_wf_types(param_env, tcx.def_span(impl1_def_id), impl1_def_id); let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id); - let impl2_substs = - translate_substs(infcx, param_env, impl1_def_id.to_def_id(), impl1_substs, impl2_node); + let impl1_span = tcx.def_span(impl1_def_id); + let impl2_substs = translate_substs_with_cause( + infcx, + param_env, + impl1_def_id.to_def_id(), + impl1_substs, + impl2_node, + |_, span| { + traits::ObligationCause::new( + impl1_span, + impl1_def_id, + traits::ObligationCauseCode::BindingObligation(impl2_node.def_id(), span), + ) + }, + ); let errors = ocx.select_all_or_error(); if !errors.is_empty() { diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs index d53c429ca15..0cd2fc1aa29 100644 --- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs +++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs @@ -210,6 +210,9 @@ fn insert_required_predicates_to_be_wf<'tcx>( ); } + // FIXME(inherent_associated_types): Handle this case properly. + ty::Alias(ty::Inherent, _) => {} + _ => {} } } |
