Skip to content

Commit

Permalink
Make hidden type registration opt-in, so that each site can be review…
Browse files Browse the repository at this point in the history
…ed on its own and we have the right defaults for trait solvers
  • Loading branch information
oli-obk committed Feb 21, 2023
1 parent 506f934 commit 018f210
Show file tree
Hide file tree
Showing 15 changed files with 59 additions and 31 deletions.
5 changes: 3 additions & 2 deletions compiler/rustc_borrowck/src/region_infer/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,9 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
let infcx = self
.tcx
.infer_ctxt()
// HACK This bubble is required for this tests to pass:
// type-alias-impl-trait/issue-67844-nested-opaque.rs
// HACK This ignore is required for this tests to pass:
// nested-return-type2-tait2.rs
// nested-return-type2-tait3.rs
.with_opaque_type_inference(DefiningAnchor::Ignore)
.build();
let ocx = ObligationCtxt::new(&infcx);
Expand Down
7 changes: 5 additions & 2 deletions compiler/rustc_hir_typeck/src/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -561,8 +561,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) {
// Check that E' = S'.
let cause = self.misc(hir_ty.span);
let InferOk { value: (), obligations } =
self.at(&cause, self.param_env).eq(*expected_ty, supplied_ty)?;
let InferOk { value: (), obligations } = self
.at(&cause, self.param_env)
.define_opaque_types(true)
.eq(*expected_ty, supplied_ty)?;
all_obligations.extend(obligations);
}

Expand All @@ -574,6 +576,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let cause = &self.misc(decl.output.span());
let InferOk { value: (), obligations } = self
.at(cause, self.param_env)
.define_opaque_types(true)
.eq(expected_sigs.liberated_sig.output(), supplied_output_ty)?;
all_obligations.extend(obligations);

Expand Down
12 changes: 8 additions & 4 deletions compiler/rustc_hir_typeck/src/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub);
self.commit_if_ok(|_| {
let at = self.at(&self.cause, self.fcx.param_env).define_opaque_types(true);
if self.use_lub {
self.at(&self.cause, self.fcx.param_env).lub(b, a)
at.lub(b, a)
} else {
self.at(&self.cause, self.fcx.param_env)
.sup(b, a)
at.sup(b, a)
.map(|InferOk { value: (), obligations }| InferOk { value: a, obligations })
}
})
Expand All @@ -174,7 +174,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// Best-effort try to unify these types -- we're already on the error path,
// so this will have the side-effect of making sure we have no ambiguities
// due to `[type error]` and `_` not coercing together.
let _ = self.commit_if_ok(|_| self.at(&self.cause, self.param_env).eq(a, b));
let _ = self.commit_if_ok(|_| {
self.at(&self.cause, self.param_env).define_opaque_types(true).eq(a, b)
});
return success(vec![], self.fcx.tcx.ty_error(), vec![]);
}

Expand Down Expand Up @@ -1484,6 +1486,8 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
// Another example is `break` with no argument expression.
assert!(expression_ty.is_unit(), "if let hack without unit type");
fcx.at(cause, fcx.param_env)
// needed for tests/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs
.define_opaque_types(true)
.eq_exp(label_expression_as_expected, expression_ty, self.merged_ty())
.map(|infer_ok| {
fcx.register_infer_ok_obligations(infer_ok);
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_typeck/src/demand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected: Ty<'tcx>,
actual: Ty<'tcx>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
match self.at(cause, self.param_env).sup(expected, actual) {
match self.at(cause, self.param_env).define_opaque_types(true).sup(expected, actual) {
Ok(InferOk { obligations, value: () }) => {
self.register_predicates(obligations);
None
Expand Down Expand Up @@ -143,7 +143,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected: Ty<'tcx>,
actual: Ty<'tcx>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
match self.at(cause, self.param_env).eq(expected, actual) {
match self.at(cause, self.param_env).define_opaque_types(true).eq(expected, actual) {
Ok(InferOk { obligations, value: () }) => {
self.register_predicates(obligations);
None
Expand Down
3 changes: 0 additions & 3 deletions compiler/rustc_hir_typeck/src/method/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1488,7 +1488,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
TraitCandidate(trait_ref) => self.probe(|_| {
let _ = self
.at(&ObligationCause::dummy(), self.param_env)
.define_opaque_types(false)
.sup(candidate.xform_self_ty, self_ty);
match self.select_trait_candidate(trait_ref) {
Ok(Some(traits::ImplSource::UserDefined(ref impl_data))) => {
Expand Down Expand Up @@ -1518,7 +1517,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
// First check that the self type can be related.
let sub_obligations = match self
.at(&ObligationCause::dummy(), self.param_env)
.define_opaque_types(false)
.sup(probe.xform_self_ty, self_ty)
{
Ok(InferOk { obligations, value: () }) => obligations,
Expand Down Expand Up @@ -1735,7 +1733,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
if let ProbeResult::Match = result
&& self
.at(&ObligationCause::dummy(), self.param_env)
.define_opaque_types(false)
.sup(return_ty, xform_ret_ty)
.is_err()
{
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_infer/src/infer/at.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ impl<'tcx> InferCtxt<'tcx> {
cause: &'a ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> At<'a, 'tcx> {
At { infcx: self, cause, param_env, define_opaque_types: true }
At { infcx: self, cause, param_env, define_opaque_types: false }
}

/// Forks the inference context, creating a new inference context with the same inference
Expand Down
13 changes: 8 additions & 5 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,12 +260,15 @@ pub struct InferCtxt<'tcx> {
/// The `DefId` of the item in whose context we are performing inference or typeck.
/// It is used to check whether an opaque type use is a defining use.
///
/// If it is `DefiningAnchor::Ignore`, we can't resolve opaque types here and need to bubble up
/// the obligation. This frequently happens for
/// short lived InferCtxt within queries. The opaque type obligations are forwarded
/// to the outside until the end up in an `InferCtxt` for typeck or borrowck.
/// If it is `DefiningAnchor::Ignore`, we can't resolve opaque types here and just
/// act as if we were in a defining scope. This is useful for codegen, as it reveals
/// opaque types, but some nested obligations may end up with opaque types and we don't
/// normalize obligations. It is also useful for coherence, as we want opaque types to
/// act as if they accept every type for which their bounds hold, no matter the defining scopes.
/// This is necessary as impls are accessible outside the defining scopes of types they get
/// implemented for. Finally, this is useful for sanity assertions in const eval.
///
/// It is default value is `DefiningAnchor::Error`, this way it is easier to catch errors that
/// Its default value is `DefiningAnchor::Error`, this way it is easier to catch errors that
/// might come up during inference or typeck.
pub defining_use_anchor: DefiningAnchor,

Expand Down
7 changes: 5 additions & 2 deletions compiler/rustc_infer/src/infer/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -546,8 +546,11 @@ impl<'tcx> InferCtxt<'tcx> {
origin,
);
if let Some(prev) = prev {
obligations =
self.at(&cause, param_env).eq_exp(a_is_expected, prev, hidden_ty)?.obligations;
obligations = self
.at(&cause, param_env)
.define_opaque_types(true)
.eq_exp(a_is_expected, prev, hidden_ty)?
.obligations;
}
}

Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_trait_selection/src/solve/infcx_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
rhs: T,
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
self.at(&ObligationCause::dummy(), param_env)
.define_opaque_types(false)
.eq(lhs, rhs)
.map(|InferOk { value: (), obligations }| {
obligations.into_iter().map(|o| o.into()).collect()
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_trait_selection/src/traits/coherence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ fn equate_impl_headers<'cx, 'tcx>(
selcx
.infcx
.at(&ObligationCause::dummy(), ty::ParamEnv::empty())
.define_opaque_types(true)
.eq_impl_headers(impl1_header, impl2_header)
.map(|infer_ok| infer_ok.obligations)
.ok()
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_trait_selection/src/traits/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
{
self.infcx
.at(cause, param_env)
.define_opaque_types(true)
.eq_exp(a_is_expected, a, b)
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
}
Expand All @@ -141,6 +142,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
) -> Result<(), TypeError<'tcx>> {
self.infcx
.at(cause, param_env)
.define_opaque_types(true)
.eq(expected, actual)
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
}
Expand All @@ -155,6 +157,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
) -> Result<(), TypeError<'tcx>> {
self.infcx
.at(cause, param_env)
.define_opaque_types(true)
.sup(expected, actual)
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
}
Expand All @@ -169,6 +172,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
) -> Result<(), TypeError<'tcx>> {
self.infcx
.at(cause, param_env)
.define_opaque_types(true)
.sup(expected, actual)
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
}
Expand Down
7 changes: 6 additions & 1 deletion compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,12 @@ fn project_and_unify_type<'cx, 'tcx>(
);
obligations.extend(new);

match infcx.at(&obligation.cause, obligation.param_env).eq(normalized, actual) {
match infcx
.at(&obligation.cause, obligation.param_env)
// This is needed to support nested opaque types like `impl Fn() -> impl Trait`
.define_opaque_types(true)
.eq(normalized, actual)
{
Ok(InferOk { obligations: inferred_obligations, value: () }) => {
obligations.extend(inferred_obligations);
ProjectAndUnifyResult::Holds(obligations)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {

self.infcx
.at(&obligation.cause, obligation.param_env)
// needed for tests/ui/type-alias-impl-trait/assoc-projection-ice.rs
.define_opaque_types(true)
.sup(obligation_trait_ref, expected_trait_ref)
.map(|InferOk { mut obligations, .. }| {
obligations.extend(nested);
Expand Down
8 changes: 0 additions & 8 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1752,7 +1752,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
});
self.infcx
.at(&obligation.cause, obligation.param_env)
.define_opaque_types(false)
.sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound)
.map(|InferOk { obligations: _, value: () }| {
// This method is called within a probe, so we can't have
Expand Down Expand Up @@ -1815,7 +1814,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let is_match = self
.infcx
.at(&obligation.cause, obligation.param_env)
.define_opaque_types(false)
.sup(obligation.predicate, infer_projection)
.map_or(false, |InferOk { obligations, value: () }| {
self.evaluate_predicates_recursively(
Expand Down Expand Up @@ -2507,7 +2505,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let InferOk { obligations, .. } = self
.infcx
.at(&cause, obligation.param_env)
.define_opaque_types(false)
.eq(placeholder_obligation_trait_ref, impl_trait_ref)
.map_err(|e| {
debug!("match_impl: failed eq_trait_refs due to `{}`", e.to_string(self.tcx()))
Expand Down Expand Up @@ -2558,11 +2555,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
self.infcx
.at(&obligation.cause, obligation.param_env)
// We don't want predicates for opaque types to just match all other types,
// if there is an obligation on the opaque type, then that obligation must be met
// opaquely. Otherwise we'd match any obligation to the opaque type and then error
// out later.
.define_opaque_types(false)
.sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref)
.map(|InferOk { obligations, .. }| obligations)
.map_err(|_| ())
Expand Down
14 changes: 14 additions & 0 deletions tests/ui/type-alias-impl-trait/match-unification.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use std::fmt::Debug;

// check-pass

fn bar() -> impl Debug {}

fn baz(b: bool) -> Option<impl Debug> {
match b {
true => baz(false),
false => Some(bar()),
}
}

fn main() {}

0 comments on commit 018f210

Please sign in to comment.