Skip to content

Commit 34ce403

Browse files
committed
Don't build ParamEnv and do trait solving in ItemCtxts
1 parent efcbb94 commit 34ce403

24 files changed

+419
-250
lines changed

compiler/rustc_hir_analysis/src/collect.rs

+98-3
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,22 @@ 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;
4750
use crate::hir_ty_lowering::errors::assoc_tag_str;
48-
use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason};
51+
use crate::hir_ty_lowering::{
52+
FeedConstTy, HirTyLowerer, InherentAssocCandidate, RegionInferReason,
53+
};
4954

5055
pub(crate) mod dump;
5156
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_shared(
448543
&self,
449544
span: Span,

compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use rustc_trait_selection::traits::{
2424
};
2525
use smallvec::SmallVec;
2626

27+
use super::InherentAssocCandidate;
2728
use crate::errors::{
2829
self, AssocItemConstraintsNotAllowedHere, ManualImplementation, MissingTypeParams,
2930
ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits,
@@ -570,7 +571,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
570571
&self,
571572
name: Ident,
572573
self_ty: Ty<'tcx>,
573-
candidates: Vec<(DefId, (DefId, DefId))>,
574+
candidates: Vec<InherentAssocCandidate>,
574575
fulfillment_errors: Vec<FulfillmentError<'tcx>>,
575576
span: Span,
576577
assoc_tag: ty::AssocTag,
@@ -604,8 +605,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
604605
let type_candidates = candidates
605606
.iter()
606607
.take(limit)
607-
.map(|&(impl_, _)| {
608-
format!("- `{}`", tcx.at(span).type_of(impl_).instantiate_identity())
608+
.map(|cand| {
609+
format!("- `{}`", tcx.at(span).type_of(cand.impl_).instantiate_identity())
609610
})
610611
.collect::<Vec<_>>()
611612
.join("\n");

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

+38-112
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,13 @@ 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, AssocTag, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty,
42-
TyCtxt, TypeVisitableExt, TypingMode, Upcast, fold_regions,
41+
self, AssocTag, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt,
42+
TypeVisitableExt, TypingMode, Upcast, fold_regions,
4343
};
4444
use rustc_middle::{bug, span_bug};
4545
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
@@ -48,7 +48,7 @@ use rustc_span::edit_distance::find_best_match_for_name;
4848
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
4949
use rustc_trait_selection::infer::InferCtxtExt;
5050
use rustc_trait_selection::traits::wf::object_region_bounds;
51-
use rustc_trait_selection::traits::{self, ObligationCtxt};
51+
use rustc_trait_selection::traits::{self, FulfillmentError};
5252
use tracing::{debug, instrument};
5353

5454
use self::errors::assoc_tag_str;
@@ -101,6 +101,13 @@ pub enum RegionInferReason<'a> {
101101
OutlivesBound,
102102
}
103103

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

160+
fn select_inherent_assoc_candidates(
161+
&self,
162+
span: Span,
163+
self_ty: Ty<'tcx>,
164+
candidates: &Vec<InherentAssocCandidate>,
165+
) -> (Vec<InherentAssocCandidate>, Vec<FulfillmentError<'tcx>>);
166+
153167
/// Lower an associated type/const (from a trait) to a projection.
154168
///
155169
/// This method has to be defined by the concrete lowering context because
@@ -1513,48 +1527,32 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
15131527
.filter_map(|&impl_| {
15141528
let (item, scope) =
15151529
self.probe_assoc_item_unchecked(name, assoc_tag, block, impl_)?;
1516-
Some((impl_, (item.def_id, scope)))
1530+
Some(InherentAssocCandidate { impl_, assoc_item: item.def_id, scope })
15171531
})
15181532
.collect();
15191533

1520-
if candidates.is_empty() {
1521-
return Ok(None);
1522-
}
1523-
1524-
//
1525-
// Select applicable inherent associated type candidates modulo regions.
1526-
//
1527-
1528-
// In contexts that have no inference context, just make a new one.
1529-
// We do need a local variable to store it, though.
1530-
let infcx = match self.infcx() {
1531-
Some(infcx) => infcx,
1532-
None => {
1533-
assert!(!self_ty.has_infer());
1534-
&tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis())
1535-
}
1536-
};
1534+
let (applicable_candidates, fulfillment_errors) =
1535+
self.select_inherent_assoc_candidates(span, self_ty, &candidates);
15371536

1538-
// FIXME(inherent_associated_types): Acquiring the ParamEnv this early leads to cycle errors
1539-
// when inside of an ADT (#108491) or where clause.
1540-
let param_env = tcx.param_env(block.owner);
1537+
let InherentAssocCandidate { impl_, assoc_item, scope: def_scope } =
1538+
match &applicable_candidates[..] {
1539+
&[] => Err(self.complain_about_inherent_assoc_not_found(
1540+
name,
1541+
self_ty,
1542+
candidates,
1543+
fulfillment_errors,
1544+
span,
1545+
assoc_tag,
1546+
)),
15411547

1542-
let mut universes = if self_ty.has_escaping_bound_vars() {
1543-
vec![None; self_ty.outer_exclusive_binder().as_usize()]
1544-
} else {
1545-
vec![]
1546-
};
1548+
&[applicable_candidate] => Ok(applicable_candidate),
15471549

1548-
let (impl_, (assoc_item, def_scope)) = crate::traits::with_replaced_escaping_bound_vars(
1549-
infcx,
1550-
&mut universes,
1551-
self_ty,
1552-
|self_ty| {
1553-
self.select_inherent_assoc_candidates(
1554-
infcx, name, span, self_ty, param_env, candidates, assoc_tag,
1555-
)
1556-
},
1557-
)?;
1550+
&[_, ..] => Err(self.complain_about_ambiguous_inherent_assoc(
1551+
name,
1552+
candidates.into_iter().map(|cand| cand.assoc_item).collect(),
1553+
span,
1554+
)),
1555+
}?;
15581556

15591557
self.check_assoc_item(assoc_item, name, def_scope, block, span);
15601558

@@ -1571,78 +1569,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
15711569
Ok(Some((assoc_item, args)))
15721570
}
15731571

1574-
fn select_inherent_assoc_candidates(
1575-
&self,
1576-
infcx: &InferCtxt<'tcx>,
1577-
name: Ident,
1578-
span: Span,
1579-
self_ty: Ty<'tcx>,
1580-
param_env: ParamEnv<'tcx>,
1581-
candidates: Vec<(DefId, (DefId, DefId))>,
1582-
assoc_tag: ty::AssocTag,
1583-
) -> Result<(DefId, (DefId, DefId)), ErrorGuaranteed> {
1584-
let tcx = self.tcx();
1585-
let mut fulfillment_errors = Vec::new();
1586-
1587-
let applicable_candidates: Vec<_> = candidates
1588-
.iter()
1589-
.copied()
1590-
.filter(|&(impl_, _)| {
1591-
infcx.probe(|_| {
1592-
let ocx = ObligationCtxt::new_with_diagnostics(infcx);
1593-
let self_ty = ocx.normalize(&ObligationCause::dummy(), param_env, self_ty);
1594-
1595-
let impl_args = infcx.fresh_args_for_item(span, impl_);
1596-
let impl_ty = tcx.type_of(impl_).instantiate(tcx, impl_args);
1597-
let impl_ty = ocx.normalize(&ObligationCause::dummy(), param_env, impl_ty);
1598-
1599-
// Check that the self types can be related.
1600-
if ocx.eq(&ObligationCause::dummy(), param_env, impl_ty, self_ty).is_err() {
1601-
return false;
1602-
}
1603-
1604-
// Check whether the impl imposes obligations we have to worry about.
1605-
let impl_bounds = tcx.predicates_of(impl_).instantiate(tcx, impl_args);
1606-
let impl_bounds =
1607-
ocx.normalize(&ObligationCause::dummy(), param_env, impl_bounds);
1608-
let impl_obligations = traits::predicates_for_generics(
1609-
|_, _| ObligationCause::dummy(),
1610-
param_env,
1611-
impl_bounds,
1612-
);
1613-
ocx.register_obligations(impl_obligations);
1614-
1615-
let mut errors = ocx.select_where_possible();
1616-
if !errors.is_empty() {
1617-
fulfillment_errors.append(&mut errors);
1618-
return false;
1619-
}
1620-
1621-
true
1622-
})
1623-
})
1624-
.collect();
1625-
1626-
match &applicable_candidates[..] {
1627-
&[] => Err(self.complain_about_inherent_assoc_not_found(
1628-
name,
1629-
self_ty,
1630-
candidates,
1631-
fulfillment_errors,
1632-
span,
1633-
assoc_tag,
1634-
)),
1635-
1636-
&[applicable_candidate] => Ok(applicable_candidate),
1637-
1638-
&[_, ..] => Err(self.complain_about_ambiguous_inherent_assoc(
1639-
name,
1640-
applicable_candidates.into_iter().map(|(_, (candidate, _))| candidate).collect(),
1641-
span,
1642-
)),
1643-
}
1644-
}
1645-
16461572
/// Given name and kind search for the assoc item in the provided scope and check if it's accessible[^1].
16471573
///
16481574
/// [^1]: I.e., accessible in the provided scope wrt. visibility and stability.

0 commit comments

Comments
 (0)