Skip to content

Commit 701d3b8

Browse files
committed
Don't build ParamEnv and do trait solving in ItemCtxts
1 parent 52bf0cf commit 701d3b8

27 files changed

+418
-279
lines changed

compiler/rustc_hir_analysis/src/collect.rs

Lines changed: 98 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,21 @@ use rustc_infer::traits::ObligationCause;
3535
use rustc_middle::hir::nested_filter;
3636
use rustc_middle::query::Providers;
3737
use rustc_middle::ty::util::{Discr, IntTypeExt};
38-
use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypingMode, fold_regions};
38+
use rustc_middle::ty::{
39+
self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypeFolder, TypeSuperFoldable,
40+
TypeVisitableExt, TypingMode, fold_regions,
41+
};
3942
use rustc_middle::{bug, span_bug};
4043
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
4144
use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName;
4245
use rustc_trait_selection::infer::InferCtxtExt;
43-
use rustc_trait_selection::traits::ObligationCtxt;
46+
use rustc_trait_selection::traits::{FulfillmentError, ObligationCtxt};
4447
use tracing::{debug, instrument};
4548

4649
use crate::errors;
47-
use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason};
50+
use crate::hir_ty_lowering::{
51+
FeedConstTy, HirTyLowerer, InherentAssocCandidate, RegionInferReason,
52+
};
4853

4954
pub(crate) mod dump;
5055
mod generics_of;
@@ -444,6 +449,96 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
444449
self.tcx.at(span).type_param_predicates((self.item_def_id, def_id, assoc_ident))
445450
}
446451

452+
fn select_inherent_assoc_candidates(
453+
&self,
454+
span: Span,
455+
self_ty: Ty<'tcx>,
456+
candidates: &Vec<InherentAssocCandidate>,
457+
) -> (Vec<InherentAssocCandidate>, Vec<FulfillmentError<'tcx>>) {
458+
// This is all rather hacky. We attempt to unify impl headers against this self ty
459+
// (even though we aren't really in a position to do so) as users of IATs in signatures
460+
// are unable to explicitly disambiguate which impl to use other than by specifying the
461+
// self type.
462+
463+
struct ReplaceAliasesWithInfer<'tcx, 'a>(&'a InferCtxt<'tcx>);
464+
465+
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceAliasesWithInfer<'tcx, '_> {
466+
fn cx(&self) -> TyCtxt<'tcx> {
467+
self.0.tcx
468+
}
469+
470+
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
471+
if let ty::Alias(_, _) = ty.kind() {
472+
return self.0.next_ty_var(DUMMY_SP);
473+
}
474+
475+
ty.super_fold_with(self)
476+
}
477+
478+
fn fold_const(&mut self, ct: Const<'tcx>) -> Const<'tcx> {
479+
if let ty::ConstKind::Unevaluated(_) = ct.kind() {
480+
return self.0.next_const_var(DUMMY_SP);
481+
}
482+
483+
ct.super_fold_with(self)
484+
}
485+
}
486+
487+
assert!(!self_ty.has_infer());
488+
let infcx =
489+
self.tcx().infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis());
490+
491+
// We replace all the aliases in the self type with infer vars to avoid filtering out
492+
// candidates that only differ in how normalized alias is. This shouldn't be necessary
493+
// under the new solver which emits alias relate goals instead of expecting inputs to
494+
// already be fully normalized. FIXME(-Znext-solver)
495+
//
496+
// We don't just call the normal normalization routine here as we can't provide the
497+
// correct `ParamEnv` and it seems dubious to invoke arbitrary trait solving under
498+
// the wrong `ParamEnv`.
499+
let self_ty = ReplaceAliasesWithInfer(&infcx).fold_ty(self_ty);
500+
501+
let mut universes = if self_ty.has_escaping_bound_vars() {
502+
vec![None; self_ty.outer_exclusive_binder().as_usize()]
503+
} else {
504+
vec![]
505+
};
506+
507+
let candidates = rustc_trait_selection::traits::with_replaced_escaping_bound_vars(
508+
&infcx,
509+
&mut universes,
510+
self_ty,
511+
|self_ty| {
512+
infcx.probe(|_| {
513+
candidates
514+
.into_iter()
515+
.filter(|&&InherentAssocCandidate { impl_, .. }| {
516+
let impl_ty = self
517+
.tcx()
518+
.type_of(impl_)
519+
.instantiate(self.tcx(), infcx.fresh_args_for_item(span, impl_));
520+
// See comment on doing this operation for `self_ty`
521+
let impl_ty = ReplaceAliasesWithInfer(&infcx).fold_ty(impl_ty);
522+
523+
use rustc_trait_selection::infer::DefineOpaqueTypes;
524+
infcx
525+
// Using an empty `ParamEnv` is pretty weird but we don't actually
526+
// do anything with any of the returned obligations so it doesn't
527+
// matter too much. Building the correct `ParamEnv` would also result
528+
// in undesirable query cycles.
529+
.at(&ObligationCause::dummy(), ty::ParamEnv::empty())
530+
.eq(DefineOpaqueTypes::No, self_ty, impl_ty)
531+
.is_ok()
532+
})
533+
.cloned()
534+
.collect()
535+
})
536+
},
537+
);
538+
539+
(candidates, vec![])
540+
}
541+
447542
fn lower_assoc_item_path(
448543
&self,
449544
span: Span,

compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use rustc_trait_selection::traits::{
2626
use smallvec::SmallVec;
2727
use tracing::debug;
2828

29+
use super::InherentAssocCandidate;
2930
use crate::errors::{
3031
self, AssocItemConstraintsNotAllowedHere, ManualImplementation, MissingTypeParams,
3132
ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits,
@@ -742,7 +743,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
742743
&self,
743744
name: Ident,
744745
self_ty: Ty<'tcx>,
745-
candidates: Vec<(DefId, (DefId, DefId))>,
746+
candidates: Vec<InherentAssocCandidate>,
746747
fulfillment_errors: Vec<FulfillmentError<'tcx>>,
747748
span: Span,
748749
assoc_tag: ty::AssocTag,
@@ -776,8 +777,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
776777
let type_candidates = candidates
777778
.iter()
778779
.take(limit)
779-
.map(|&(impl_, _)| {
780-
format!("- `{}`", tcx.at(span).type_of(impl_).instantiate_identity())
780+
.map(|cand| {
781+
format!("- `{}`", tcx.at(span).type_of(cand.impl_).instantiate_identity())
781782
})
782783
.collect::<Vec<_>>()
783784
.join("\n");

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

Lines changed: 38 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -33,21 +33,21 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
3333
use rustc_hir::def_id::{DefId, LocalDefId};
3434
use rustc_hir::{self as hir, AnonConst, GenericArg, GenericArgs, HirId};
3535
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
36-
use rustc_infer::traits::ObligationCause;
36+
use rustc_macros::{TypeFoldable, TypeVisitable};
3737
use rustc_middle::middle::stability::AllowUnstable;
3838
use rustc_middle::mir::interpret::LitToConstInput;
3939
use rustc_middle::ty::print::PrintPolyTraitRefExt as _;
4040
use rustc_middle::ty::{
41-
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt,
42-
TypeVisitableExt, TypingMode, Upcast, fold_regions,
41+
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt,
42+
TypingMode, Upcast, fold_regions,
4343
};
4444
use rustc_middle::{bug, span_bug};
4545
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
4646
use rustc_session::parse::feature_err;
4747
use rustc_span::{DUMMY_SP, Ident, Span, kw, sym};
4848
use rustc_trait_selection::infer::InferCtxtExt;
4949
use rustc_trait_selection::traits::wf::object_region_bounds;
50-
use rustc_trait_selection::traits::{self, ObligationCtxt};
50+
use rustc_trait_selection::traits::{self, FulfillmentError};
5151
use tracing::{debug, instrument};
5252

5353
use crate::check::check_abi_fn_ptr;
@@ -99,6 +99,13 @@ pub enum RegionInferReason<'a> {
9999
OutlivesBound,
100100
}
101101

102+
#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Debug)]
103+
pub struct InherentAssocCandidate {
104+
pub impl_: DefId,
105+
pub assoc_item: DefId,
106+
pub scope: DefId,
107+
}
108+
102109
/// A context which can lower type-system entities from the [HIR][hir] to
103110
/// the [`rustc_middle::ty`] representation.
104111
///
@@ -148,6 +155,13 @@ pub trait HirTyLowerer<'tcx> {
148155
assoc_ident: Ident,
149156
) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]>;
150157

158+
fn select_inherent_assoc_candidates(
159+
&self,
160+
span: Span,
161+
self_ty: Ty<'tcx>,
162+
candidates: &Vec<InherentAssocCandidate>,
163+
) -> (Vec<InherentAssocCandidate>, Vec<FulfillmentError<'tcx>>);
164+
151165
/// Lower a path to an associated item (of a trait) to a projection.
152166
///
153167
/// This method has to be defined by the concrete lowering context because
@@ -1441,48 +1455,32 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
14411455
.filter_map(|&impl_| {
14421456
let (item, scope) =
14431457
self.probe_assoc_item_unchecked(name, assoc_tag, block, impl_)?;
1444-
Some((impl_, (item.def_id, scope)))
1458+
Some(InherentAssocCandidate { impl_, assoc_item: item.def_id, scope })
14451459
})
14461460
.collect();
14471461

1448-
if candidates.is_empty() {
1449-
return Ok(None);
1450-
}
1451-
1452-
//
1453-
// Select applicable inherent associated type candidates modulo regions.
1454-
//
1455-
1456-
// In contexts that have no inference context, just make a new one.
1457-
// We do need a local variable to store it, though.
1458-
let infcx = match self.infcx() {
1459-
Some(infcx) => infcx,
1460-
None => {
1461-
assert!(!self_ty.has_infer());
1462-
&tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis())
1463-
}
1464-
};
1462+
let (applicable_candidates, fulfillment_errors) =
1463+
self.select_inherent_assoc_candidates(span, self_ty, &candidates);
14651464

1466-
// FIXME(inherent_associated_types): Acquiring the ParamEnv this early leads to cycle errors
1467-
// when inside of an ADT (#108491) or where clause.
1468-
let param_env = tcx.param_env(block.owner);
1465+
let InherentAssocCandidate { impl_, assoc_item, scope: def_scope } =
1466+
match &applicable_candidates[..] {
1467+
&[] => Err(self.report_unresolved_inherent_assoc_item(
1468+
name,
1469+
self_ty,
1470+
candidates,
1471+
fulfillment_errors,
1472+
span,
1473+
assoc_tag,
1474+
)),
14691475

1470-
let mut universes = if self_ty.has_escaping_bound_vars() {
1471-
vec![None; self_ty.outer_exclusive_binder().as_usize()]
1472-
} else {
1473-
vec![]
1474-
};
1476+
&[applicable_candidate] => Ok(applicable_candidate),
14751477

1476-
let (impl_, (assoc_item, def_scope)) = crate::traits::with_replaced_escaping_bound_vars(
1477-
infcx,
1478-
&mut universes,
1479-
self_ty,
1480-
|self_ty| {
1481-
self.select_inherent_assoc_candidates(
1482-
infcx, name, span, self_ty, param_env, candidates, assoc_tag,
1483-
)
1484-
},
1485-
)?;
1478+
&[_, ..] => Err(self.report_ambiguous_inherent_assoc_item(
1479+
name,
1480+
candidates.into_iter().map(|cand| cand.assoc_item).collect(),
1481+
span,
1482+
)),
1483+
}?;
14861484

14871485
self.check_assoc_item(assoc_item, name, def_scope, block, span);
14881486

@@ -1499,78 +1497,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
14991497
Ok(Some((assoc_item, args)))
15001498
}
15011499

1502-
fn select_inherent_assoc_candidates(
1503-
&self,
1504-
infcx: &InferCtxt<'tcx>,
1505-
name: Ident,
1506-
span: Span,
1507-
self_ty: Ty<'tcx>,
1508-
param_env: ParamEnv<'tcx>,
1509-
candidates: Vec<(DefId, (DefId, DefId))>,
1510-
assoc_tag: ty::AssocTag,
1511-
) -> Result<(DefId, (DefId, DefId)), ErrorGuaranteed> {
1512-
let tcx = self.tcx();
1513-
let mut fulfillment_errors = Vec::new();
1514-
1515-
let applicable_candidates: Vec<_> = candidates
1516-
.iter()
1517-
.copied()
1518-
.filter(|&(impl_, _)| {
1519-
infcx.probe(|_| {
1520-
let ocx = ObligationCtxt::new_with_diagnostics(infcx);
1521-
let self_ty = ocx.normalize(&ObligationCause::dummy(), param_env, self_ty);
1522-
1523-
let impl_args = infcx.fresh_args_for_item(span, impl_);
1524-
let impl_ty = tcx.type_of(impl_).instantiate(tcx, impl_args);
1525-
let impl_ty = ocx.normalize(&ObligationCause::dummy(), param_env, impl_ty);
1526-
1527-
// Check that the self types can be related.
1528-
if ocx.eq(&ObligationCause::dummy(), param_env, impl_ty, self_ty).is_err() {
1529-
return false;
1530-
}
1531-
1532-
// Check whether the impl imposes obligations we have to worry about.
1533-
let impl_bounds = tcx.predicates_of(impl_).instantiate(tcx, impl_args);
1534-
let impl_bounds =
1535-
ocx.normalize(&ObligationCause::dummy(), param_env, impl_bounds);
1536-
let impl_obligations = traits::predicates_for_generics(
1537-
|_, _| ObligationCause::dummy(),
1538-
param_env,
1539-
impl_bounds,
1540-
);
1541-
ocx.register_obligations(impl_obligations);
1542-
1543-
let mut errors = ocx.select_where_possible();
1544-
if !errors.is_empty() {
1545-
fulfillment_errors.append(&mut errors);
1546-
return false;
1547-
}
1548-
1549-
true
1550-
})
1551-
})
1552-
.collect();
1553-
1554-
match &applicable_candidates[..] {
1555-
&[] => Err(self.report_unresolved_inherent_assoc_item(
1556-
name,
1557-
self_ty,
1558-
candidates,
1559-
fulfillment_errors,
1560-
span,
1561-
assoc_tag,
1562-
)),
1563-
1564-
&[applicable_candidate] => Ok(applicable_candidate),
1565-
1566-
&[_, ..] => Err(self.report_ambiguous_inherent_assoc_item(
1567-
name,
1568-
applicable_candidates.into_iter().map(|(_, (candidate, _))| candidate).collect(),
1569-
span,
1570-
)),
1571-
}
1572-
}
1573-
15741500
/// Given name and kind search for the assoc item in the provided scope and check if it's accessible[^1].
15751501
///
15761502
/// [^1]: I.e., accessible in the provided scope wrt. visibility and stability.

0 commit comments

Comments
 (0)