diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index c0cd54cc916e0..a1c84d2abb5ed 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -28,8 +28,8 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{walk_generics, Visitor as _}; use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; -use rustc_infer::traits::ObligationCause; +use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt}; +use rustc_infer::traits::{ObligationCause, PredicateObligations}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef}; @@ -46,7 +46,9 @@ use rustc_trait_selection::traits::error_reporting::{ report_object_safety_error, suggestions::NextTypeParamName, }; use rustc_trait_selection::traits::wf::object_region_bounds; -use rustc_trait_selection::traits::{self, astconv_object_safety_violations, ObligationCtxt}; +use rustc_trait_selection::traits::{ + self, astconv_object_safety_violations, NormalizeExt, ObligationCtxt, +}; use smallvec::{smallvec, SmallVec}; use std::collections::BTreeSet; @@ -127,6 +129,8 @@ pub trait AstConv<'tcx> { fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span); + fn register_predicate_obligations(&self, obligations: PredicateObligations<'tcx>); + fn astconv(&self) -> &dyn AstConv<'tcx> where Self: Sized, @@ -2234,7 +2238,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut fulfillment_errors = Vec::new(); let mut applicable_candidates: Vec<_> = candidates .iter() - .filter_map(|&(impl_, (assoc_item, def_scope))| { + .filter_map(|&(impl_, item)| { infcx.probe(|_| { let ocx = ObligationCtxt::new_in_snapshot(&infcx); @@ -2250,15 +2254,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // 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 = 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(); @@ -2267,8 +2268,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { return None; } - // FIXME(fmease): Unsolved vars can escape this InferCtxt snapshot. - Some((assoc_item, def_scope, infcx.resolve_vars_if_possible(impl_substs))) + let impl_substs = if !self.allow_ty_infer() { + let substs = infcx.resolve_vars_if_possible(impl_substs); + assert!(!substs.needs_infer()); + Some(substs) + } else { + None + }; + + Some((item, impl_, impl_substs)) }) }) .collect(); @@ -2276,17 +2284,50 @@ 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(((assoc_item, def_scope), impl_, probe_impl_substs)) = + 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. + // FIXME(fmease, inherent_associated_types): Register WF obligations for the Self type. + // At the moment, we don't regionck the Self type or the substitutions. + + let impl_substs; + if let Some(probe_impl_substs) = probe_impl_substs { + impl_substs = probe_impl_substs; + } else { + impl_substs = infcx.fresh_item_substs(impl_); + + let impl_bounds = tcx.predicates_of(impl_); + let impl_bounds = impl_bounds.instantiate(tcx, impl_substs); + let InferOk { value: impl_bounds, obligations: norm_obligations } = + infcx.at(&cause, param_env).normalize(impl_bounds); + self.register_predicate_obligations(norm_obligations); + let impl_obligations = + traits::predicates_for_generics(|_, _| cause.clone(), param_env, impl_bounds); + self.register_predicate_obligations(impl_obligations.collect()); + + let impl_ty = tcx.type_of(impl_); + let impl_ty = impl_ty.subst(tcx, impl_substs); + let InferOk { value: impl_ty, obligations: norm_obligations } = + infcx.at(&cause, param_env).normalize(impl_ty); + self.register_predicate_obligations(norm_obligations); + + match infcx.at(&cause, param_env).eq(impl_ty, self_ty) { + Ok(ok) => self.register_predicate_obligations(ok.obligations), + Err(_) => { + tcx.sess.delay_span_bug( + span, + &format!("{self_ty:?} was a subtype of {impl_ty:?} but now it is not?"), + ); + } + } + } let item_substs = self.create_substs_for_associated_item(span, assoc_item, segment, impl_substs); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index ed3d50bfafa8f..0513b0bfc657d 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -26,7 +26,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{GenericParamKind, Node}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; -use rustc_infer::traits::ObligationCause; +use rustc_infer::traits::{ObligationCause, PredicateObligations}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::query::Providers; use rustc_middle::ty::util::{Discr, IntTypeExt}; @@ -516,6 +516,10 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { // There's no place to record types from signatures? } + fn register_predicate_obligations(&self, _: PredicateObligations<'tcx>) { + // There's no place to track this, so just let it go. + } + fn infcx(&self) -> Option<&InferCtxt<'tcx>> { None } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 3814ddaf73f44..d46636a8db4cb 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -6,6 +6,7 @@ mod suggestions; pub use _impl::*; use rustc_errors::ErrorGuaranteed; +use rustc_infer::traits::PredicateObligations; pub use suggestions::*; use crate::coercion::DynamicCoerceMany; @@ -326,6 +327,10 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { self.write_ty(hir_id, ty) } + fn register_predicate_obligations(&self, obligations: PredicateObligations<'tcx>) { + self.register_predicates(obligations) + } + fn infcx(&self) -> Option<&infer::InferCtxt<'tcx>> { Some(&self.infcx) } diff --git a/tests/ui/associated-inherent-types/bugs/ice-substitution.rs b/tests/ui/associated-inherent-types/bugs/ice-substitution.rs deleted file mode 100644 index 53ac79e0561ba..0000000000000 --- a/tests/ui/associated-inherent-types/bugs/ice-substitution.rs +++ /dev/null @@ -1,23 +0,0 @@ -// known-bug: unknown -// failure-status: 101 -// normalize-stderr-test "note: .*\n\n" -> "" -// normalize-stderr-test "thread 'rustc' panicked.*\n" -> "" -// rustc-env:RUST_BACKTRACE=0 - -// FIXME: I presume a type variable that couldn't be solved by `resolve_vars_if_possible` -// escapes the InferCtxt snapshot. - -#![feature(inherent_associated_types)] -#![allow(incomplete_features)] - -struct Cont(T); - -impl Cont { - type Out = Vec; -} - -pub fn weird(x: T) { - let _: Cont<_>::Out = vec![true]; -} - -fn main() {} diff --git a/tests/ui/associated-inherent-types/bugs/ice-substitution.stderr b/tests/ui/associated-inherent-types/bugs/ice-substitution.stderr deleted file mode 100644 index 7b0d1c5051624..0000000000000 --- a/tests/ui/associated-inherent-types/bugs/ice-substitution.stderr +++ /dev/null @@ -1,6 +0,0 @@ -error: the compiler unexpectedly panicked. this is a bug. - -query stack during panic: -#0 [typeck] type-checking `weird` -#1 [typeck_item_bodies] type-checking all item bodies -end of query stack diff --git a/tests/ui/associated-inherent-types/bugs/inference-fail.rs b/tests/ui/associated-inherent-types/bugs/inference-fail.rs deleted file mode 100644 index a920b412b1a49..0000000000000 --- a/tests/ui/associated-inherent-types/bugs/inference-fail.rs +++ /dev/null @@ -1,15 +0,0 @@ -// known-bug: unknown - -#![feature(inherent_associated_types)] -#![allow(incomplete_features)] - -struct S(T); - -impl S<()> { - type P = i128; -} - -fn main() { - // We fail to infer `_ == ()` here. - let _: S<_>::P; -} diff --git a/tests/ui/associated-inherent-types/former-subst-ice.rs b/tests/ui/associated-inherent-types/former-subst-ice.rs new file mode 100644 index 0000000000000..48390b9430b60 --- /dev/null +++ b/tests/ui/associated-inherent-types/former-subst-ice.rs @@ -0,0 +1,16 @@ +// check-pass + +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] + +struct Cont(T); + +impl Cont { + type Out = Vec; +} + +pub fn weird(x: T) { + let _: Cont<_>::Out = vec![true]; +} + +fn main() {} diff --git a/tests/ui/associated-inherent-types/inference-fail.rs b/tests/ui/associated-inherent-types/inference-fail.rs new file mode 100644 index 0000000000000..939a4ff60f2bb --- /dev/null +++ b/tests/ui/associated-inherent-types/inference-fail.rs @@ -0,0 +1,11 @@ +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] + +struct S(T); + +impl S { type P = (); } + +fn main() { + // There is no way to infer this type. + let _: S<_>::P = (); //~ ERROR type annotations needed +} diff --git a/tests/ui/associated-inherent-types/bugs/inference-fail.stderr b/tests/ui/associated-inherent-types/inference-fail.stderr similarity index 58% rename from tests/ui/associated-inherent-types/bugs/inference-fail.stderr rename to tests/ui/associated-inherent-types/inference-fail.stderr index 425691bd6c4f6..3a07a79f64d1c 100644 --- a/tests/ui/associated-inherent-types/bugs/inference-fail.stderr +++ b/tests/ui/associated-inherent-types/inference-fail.stderr @@ -1,8 +1,8 @@ error[E0282]: type annotations needed - --> $DIR/inference-fail.rs:14:14 + --> $DIR/inference-fail.rs:10:12 | -LL | let _: S<_>::P; - | ^ cannot infer type +LL | let _: S<_>::P = (); + | ^^^^^^^ cannot infer type error: aborting due to previous error diff --git a/tests/ui/associated-inherent-types/inference.rs b/tests/ui/associated-inherent-types/inference.rs new file mode 100644 index 0000000000000..38179214fa124 --- /dev/null +++ b/tests/ui/associated-inherent-types/inference.rs @@ -0,0 +1,39 @@ +// Testing inference capabilities. +// check-pass + +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] + +use std::convert::identity; + +struct Container(T); + +impl Container { + type Sink = (); +} + +impl Container { + type Thing = Any; +} + +impl Container<(T, ())> { + type Output = ((), Wrapped); +} + +fn main() { + // Inferred via the Self type of the impl. + let _: Container<_>::Sink; + + // Inferred via the RHS: + + let _: Container<_>::Thing = 0; + + let _: Container>::Thing = Wrapped(false); + + let _: Container<_>::Output = (drop(1), Wrapped("...")); + + let binding: Container<_>::Thing = Default::default(); // unsolved at this point + identity::(binding); // constrained and solved here +} + +struct Wrapped(T); diff --git a/tests/ui/associated-inherent-types/unsatisfied-bounds-inferred-type.rs b/tests/ui/associated-inherent-types/unsatisfied-bounds-inferred-type.rs new file mode 100644 index 0000000000000..d081c4d5b78e6 --- /dev/null +++ b/tests/ui/associated-inherent-types/unsatisfied-bounds-inferred-type.rs @@ -0,0 +1,12 @@ +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] + +struct S(T); + +impl S { + type T = T; +} + +fn main() { + let _: S<_>::T = String::new(); //~ ERROR the trait bound `String: Copy` is not satisfied +} diff --git a/tests/ui/associated-inherent-types/unsatisfied-bounds-inferred-type.stderr b/tests/ui/associated-inherent-types/unsatisfied-bounds-inferred-type.stderr new file mode 100644 index 0000000000000..44b322a4af533 --- /dev/null +++ b/tests/ui/associated-inherent-types/unsatisfied-bounds-inferred-type.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `String: Copy` is not satisfied + --> $DIR/unsatisfied-bounds-inferred-type.rs:11:12 + | +LL | let _: S<_>::T = String::new(); + | ^^^^^^^ the trait `Copy` is not implemented for `String` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`.