Skip to content

Commit 7f06dcf

Browse files
committed
support revealing uses in HIR typeck
1 parent 7cf7767 commit 7f06dcf

File tree

5 files changed

+150
-127
lines changed

5 files changed

+150
-127
lines changed

compiler/rustc_hir_typeck/src/lib.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ mod gather_locals;
3232
mod intrinsicck;
3333
mod method;
3434
mod op;
35+
mod opaque_types;
3536
mod pat;
3637
mod place_op;
3738
mod rvalue_scopes;
@@ -230,8 +231,11 @@ fn typeck_with_inspect<'tcx>(
230231

231232
fcx.select_obligations_where_possible(|_| {});
232233

233-
debug!(pending_obligations = ?fcx.fulfillment_cx.borrow().pending_obligations());
234+
if fcx.next_trait_solver() {
235+
fcx.handle_opaque_type_uses_next();
236+
}
234237

238+
debug!(pending_obligations = ?fcx.fulfillment_cx.borrow().pending_obligations());
235239
// This must be the last thing before `report_ambiguity_errors`.
236240
fcx.resolve_coroutine_interiors();
237241

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
use rustc_middle::ty::{DefiningScopeKind, EarlyBinder, OpaqueHiddenType, OpaqueTypeKey, Ty};
2+
use rustc_trait_selection::opaque_types::{
3+
InvalidOpaqueTypeArgs, check_opaque_type_parameter_valid,
4+
};
5+
6+
use crate::FnCtxt;
7+
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
8+
pub(super) fn handle_opaque_type_uses_next(&mut self) {
9+
// We clone the opaques instead of stealing them here as they are still used for
10+
// normalization in the next generation trait solver.
11+
//
12+
// FIXME(-Znext-solver): Opaque types defined after this would simply get dropped
13+
// at the end of typeck. Ideally we can feed some query here to no longer define
14+
// new opaque uses but instead always reveal by using the definitions inferred here.
15+
let opaque_types: Vec<_> = self.infcx.clone_opaque_types().into_iter().collect();
16+
self.collect_defining_uses(&opaque_types);
17+
self.apply_defining_uses(&opaque_types);
18+
}
19+
20+
fn collect_defining_uses(
21+
&mut self,
22+
opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
23+
) {
24+
let tcx = self.tcx;
25+
let typeck_results = &mut *self.typeck_results.borrow_mut();
26+
for &(opaque_type_key, hidden_type) in opaque_types {
27+
let opaque_type_key = self.resolve_vars_if_possible(opaque_type_key);
28+
let hidden_type = self.resolve_vars_if_possible(hidden_type);
29+
30+
match check_opaque_type_parameter_valid(
31+
&self,
32+
opaque_type_key,
33+
hidden_type.span,
34+
DefiningScopeKind::HirTypeck,
35+
) {
36+
Ok(()) => {}
37+
Err(InvalidOpaqueTypeArgs::AlreadyReported(guar)) => {
38+
typeck_results
39+
.concrete_opaque_types
40+
.insert(opaque_type_key.def_id, OpaqueHiddenType::new_error(tcx, guar));
41+
}
42+
// Not a defining use, ignore and treat as revealing use instead.
43+
Err(
44+
InvalidOpaqueTypeArgs::NotAParam { .. }
45+
| InvalidOpaqueTypeArgs::DuplicateParam { .. },
46+
) => continue,
47+
}
48+
49+
let hidden_type = hidden_type.remap_generic_params_to_declaration_params(
50+
opaque_type_key,
51+
tcx,
52+
DefiningScopeKind::HirTypeck,
53+
);
54+
55+
if let Some(prev) =
56+
typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id, hidden_type)
57+
{
58+
let entry =
59+
typeck_results.concrete_opaque_types.get_mut(&opaque_type_key.def_id).unwrap();
60+
if prev.ty != hidden_type.ty {
61+
if let Some(guar) = typeck_results.tainted_by_errors {
62+
entry.ty = Ty::new_error(tcx, guar);
63+
} else {
64+
let (Ok(guar) | Err(guar)) =
65+
prev.build_mismatch_error(&hidden_type, tcx).map(|d| d.emit());
66+
entry.ty = Ty::new_error(tcx, guar);
67+
}
68+
}
69+
70+
// Pick a better span if there is one.
71+
// FIXME(oli-obk): collect multiple spans for better diagnostics down the road.
72+
entry.span = prev.span.substitute_dummy(hidden_type.span);
73+
}
74+
}
75+
76+
// FIXME(-Znext-solver): Check that all opaques have been defined hre.
77+
}
78+
79+
fn apply_defining_uses(
80+
&mut self,
81+
opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
82+
) {
83+
let tcx = self.tcx;
84+
let typeck_results = &mut *self.typeck_results.borrow_mut();
85+
for &(key, hidden_type) in opaque_types {
86+
let Some(&expected) = typeck_results.concrete_opaque_types.get(&key.def_id) else {
87+
let guar =
88+
tcx.dcx().span_err(hidden_type.span, "non-defining use in the defining scope");
89+
typeck_results
90+
.concrete_opaque_types
91+
.insert(key.def_id, OpaqueHiddenType::new_error(tcx, guar));
92+
self.set_tainted_by_errors(guar);
93+
continue;
94+
};
95+
96+
let expected = EarlyBinder::bind(expected.ty).instantiate(tcx, key.args);
97+
self.demand_eqtype(hidden_type.span, expected, hidden_type.ty);
98+
}
99+
}
100+
}

compiler/rustc_hir_typeck/src/writeback.rs

+26-17
Original file line numberDiff line numberDiff line change
@@ -560,29 +560,31 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
560560
}
561561
}
562562

563+
fn visit_opaque_types_next(&mut self) {
564+
let fcx_typeck_results = self.fcx.typeck_results.borrow();
565+
assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
566+
for (&def_id, &hidden_type) in &fcx_typeck_results.concrete_opaque_types {
567+
assert!(!hidden_type.has_infer());
568+
self.typeck_results.concrete_opaque_types.insert(def_id, hidden_type);
569+
}
570+
}
571+
563572
#[instrument(skip(self), level = "debug")]
564573
fn visit_opaque_types(&mut self) {
574+
if self.fcx.next_trait_solver() {
575+
return self.visit_opaque_types_next();
576+
}
577+
565578
let tcx = self.tcx();
566-
// We clone the opaques instead of stealing them here as they are still used for
567-
// normalization in the next generation trait solver.
568-
//
569-
// FIXME(-Znext-solver): Opaque types defined after this would simply get dropped
570-
// at the end of typeck. While this seems unlikely to happen in practice this
571-
// should still get fixed. Either by preventing writeback from defining new opaque
572-
// types or by using this function at the end of writeback and running it as a
573-
// fixpoint.
574-
let opaque_types = self.fcx.infcx.clone_opaque_types();
579+
let opaque_types = self.fcx.infcx.take_opaque_types();
575580
for (opaque_type_key, hidden_type) in opaque_types {
576581
let hidden_type = self.resolve(hidden_type, &hidden_type.span);
577582
let opaque_type_key = self.resolve(opaque_type_key, &hidden_type.span);
578-
579-
if !self.fcx.next_trait_solver() {
580-
if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind()
581-
&& alias_ty.def_id == opaque_type_key.def_id.to_def_id()
582-
&& alias_ty.args == opaque_type_key.args
583-
{
584-
continue;
585-
}
583+
if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind()
584+
&& alias_ty.def_id == opaque_type_key.def_id.to_def_id()
585+
&& alias_ty.args == opaque_type_key.args
586+
{
587+
continue;
586588
}
587589

588590
if let Err(err) = check_opaque_type_parameter_valid(
@@ -597,6 +599,13 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
597599
);
598600
}
599601

602+
if hidden_type.has_non_region_infer() {
603+
let guar = self.fcx.dcx().span_err(hidden_type.span, "hidden_type has infer");
604+
self.typeck_results
605+
.concrete_opaque_types
606+
.insert(opaque_type_key.def_id, OpaqueHiddenType::new_error(tcx, guar));
607+
continue;
608+
}
600609
let hidden_type = hidden_type.remap_generic_params_to_declaration_params(
601610
opaque_type_key,
602611
tcx,

compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs

-21
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use std::ops::ControlFlow;
44
#[cfg(feature = "nightly")]
55
use rustc_macros::HashStable_NoContext;
66
use rustc_type_ir::data_structures::{HashMap, HashSet, ensure_sufficient_stack};
7-
use rustc_type_ir::fast_reject::DeepRejectCtxt;
87
use rustc_type_ir::inherent::*;
98
use rustc_type_ir::relate::Relate;
109
use rustc_type_ir::relate::solver_relating::RelateExt;
@@ -1059,26 +1058,6 @@ where
10591058
self.add_goals(GoalSource::AliasWellFormed, goals);
10601059
}
10611060

1062-
// Do something for each opaque/hidden pair defined with `def_id` in the
1063-
// current inference context.
1064-
pub(super) fn probe_existing_opaque_ty(
1065-
&mut self,
1066-
key: ty::OpaqueTypeKey<I>,
1067-
) -> Option<(ty::OpaqueTypeKey<I>, I::Ty)> {
1068-
let mut matching =
1069-
self.delegate.clone_opaque_types_for_query_response().into_iter().filter(
1070-
|(candidate_key, _)| {
1071-
candidate_key.def_id == key.def_id
1072-
&& DeepRejectCtxt::relate_rigid_rigid(self.cx())
1073-
.args_may_unify(candidate_key.args, key.args)
1074-
},
1075-
);
1076-
let first = matching.next();
1077-
let second = matching.next();
1078-
assert_eq!(second, None);
1079-
first
1080-
}
1081-
10821061
// Try to evaluate a const, or return `None` if the const is too generic.
10831062
// This doesn't mean the const isn't evaluatable, though, and should be treated
10841063
// as an ambiguity rather than no-solution.

compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs

+19-88
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
//! Computes a normalizes-to (projection) goal for opaque types. This goal
22
//! behaves differently depending on the current `TypingMode`.
33
4-
use rustc_index::bit_set::GrowableBitSet;
54
use rustc_type_ir::inherent::*;
65
use rustc_type_ir::solve::GoalSource;
7-
use rustc_type_ir::{self as ty, Interner, TypingMode, fold_regions};
6+
use rustc_type_ir::{self as ty, GenericArgKind, Interner, TypingMode, fold_regions};
87

98
use crate::delegate::SolverDelegate;
10-
use crate::solve::{Certainty, EvalCtxt, Goal, NoSolution, QueryResult, inspect};
9+
use crate::solve::{Certainty, EvalCtxt, Goal, QueryResult};
1110

1211
impl<D, I> EvalCtxt<'_, D>
1312
where
@@ -49,54 +48,27 @@ where
4948
return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
5049
};
5150

52-
// FIXME: This may have issues when the args contain aliases...
53-
match uses_unique_placeholders_ignoring_regions(self.cx(), opaque_ty.args) {
54-
Err(NotUniqueParam::NotParam(param)) if param.is_non_region_infer() => {
55-
return self.evaluate_added_goals_and_make_canonical_response(
56-
Certainty::AMBIGUOUS,
57-
);
58-
}
59-
Err(_) => {
60-
return Err(NoSolution);
61-
}
62-
Ok(()) => {}
63-
}
64-
// Prefer opaques registered already.
65-
let opaque_type_key = ty::OpaqueTypeKey { def_id, args: opaque_ty.args };
66-
// FIXME: This also unifies the previous hidden type with the expected.
67-
//
68-
// If that fails, we insert `expected` as a new hidden type instead of
69-
// eagerly emitting an error.
70-
let existing = self.probe_existing_opaque_ty(opaque_type_key);
71-
if let Some((candidate_key, candidate_ty)) = existing {
72-
return self
73-
.probe(|result| inspect::ProbeKind::OpaqueTypeStorageLookup {
74-
result: *result,
75-
})
76-
.enter(|ecx| {
77-
for (a, b) in std::iter::zip(
78-
candidate_key.args.iter(),
79-
opaque_type_key.args.iter(),
80-
) {
81-
ecx.eq(goal.param_env, a, b)?;
82-
}
83-
ecx.eq(goal.param_env, candidate_ty, expected)?;
84-
ecx.add_item_bounds_for_hidden_type(
85-
def_id.into(),
86-
candidate_key.args,
87-
goal.param_env,
88-
candidate_ty,
89-
);
90-
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
91-
});
51+
// We structurally normalize the args to
52+
let normalized_args =
53+
cx.mk_args_from_iter(opaque_ty.args.iter().map(|arg| match arg.kind() {
54+
GenericArgKind::Lifetime(lt) => Ok(lt.into()),
55+
GenericArgKind::Type(ty) => {
56+
self.structurally_normalize_ty(goal.param_env, ty).map(Into::into)
57+
}
58+
GenericArgKind::Const(ct) => {
59+
self.structurally_normalize_const(goal.param_env, ct).map(Into::into)
60+
}
61+
}))?;
62+
63+
let opaque_type_key = ty::OpaqueTypeKey { def_id, args: normalized_args };
64+
if let Some(prev) = self.register_hidden_type_in_storage(opaque_type_key, expected)
65+
{
66+
self.eq(goal.param_env, expected, prev)?;
9267
}
9368

94-
// Otherwise, define a new opaque type
95-
let prev = self.register_hidden_type_in_storage(opaque_type_key, expected);
96-
assert_eq!(prev, None);
9769
self.add_item_bounds_for_hidden_type(
9870
def_id.into(),
99-
opaque_ty.args,
71+
normalized_args,
10072
goal.param_env,
10173
expected,
10274
);
@@ -168,44 +140,3 @@ where
168140
}
169141
}
170142
}
171-
172-
/// Checks whether each generic argument is simply a unique generic placeholder.
173-
///
174-
/// FIXME: Interner argument is needed to constrain the `I` parameter.
175-
fn uses_unique_placeholders_ignoring_regions<I: Interner>(
176-
_cx: I,
177-
args: I::GenericArgs,
178-
) -> Result<(), NotUniqueParam<I>> {
179-
let mut seen = GrowableBitSet::default();
180-
for arg in args.iter() {
181-
match arg.kind() {
182-
// Ignore regions, since we can't resolve those in a canonicalized
183-
// query in the trait solver.
184-
ty::GenericArgKind::Lifetime(_) => {}
185-
ty::GenericArgKind::Type(t) => match t.kind() {
186-
ty::Placeholder(p) => {
187-
if !seen.insert(p.var()) {
188-
return Err(NotUniqueParam::DuplicateParam(t.into()));
189-
}
190-
}
191-
_ => return Err(NotUniqueParam::NotParam(t.into())),
192-
},
193-
ty::GenericArgKind::Const(c) => match c.kind() {
194-
ty::ConstKind::Placeholder(p) => {
195-
if !seen.insert(p.var()) {
196-
return Err(NotUniqueParam::DuplicateParam(c.into()));
197-
}
198-
}
199-
_ => return Err(NotUniqueParam::NotParam(c.into())),
200-
},
201-
}
202-
}
203-
204-
Ok(())
205-
}
206-
207-
// FIXME: This should check for dupes and non-params first, then infer vars.
208-
enum NotUniqueParam<I: Interner> {
209-
DuplicateParam(I::GenericArg),
210-
NotParam(I::GenericArg),
211-
}

0 commit comments

Comments
 (0)