Skip to content

Commit a78b9d1

Browse files
committed
support non-defining uses in HIR typeck
1 parent 772566b commit a78b9d1

24 files changed

+338
-339
lines changed

compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,10 @@ impl<'tcx> TaitConstraintLocator<'tcx> {
127127
}
128128

129129
fn non_defining_use_in_defining_scope(&mut self, item_def_id: LocalDefId) {
130+
// We make sure that all opaque types get defined while
131+
// type checking the defining scope, so this error is unreachable
132+
// with the new solver.
133+
assert!(!self.tcx.next_trait_solver_globally());
130134
let guar = self.tcx.dcx().emit_err(TaitForwardCompat2 {
131135
span: self
132136
.tcx
@@ -252,9 +256,7 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>(
252256
} else if let Some(hidden_ty) = tables.concrete_opaque_types.get(&def_id) {
253257
hidden_ty.ty
254258
} else {
255-
// FIXME(-Znext-solver): This should not be necessary and we should
256-
// instead rely on inference variable fallback inside of typeck itself.
257-
259+
assert!(!tcx.next_trait_solver_globally());
258260
// We failed to resolve the opaque type or it
259261
// resolves to itself. We interpret this as the
260262
// no values of the hidden type ever being constructed,
@@ -273,6 +275,7 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>(
273275
if let Err(guar) = hir_ty.error_reported() {
274276
Ty::new_error(tcx, guar)
275277
} else {
278+
assert!(!tcx.next_trait_solver_globally());
276279
hir_ty
277280
}
278281
}

compiler/rustc_hir_analysis/src/errors.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ pub(crate) struct UnconstrainedOpaqueType {
413413
#[derive(Diagnostic)]
414414
#[diag(hir_analysis_tait_forward_compat2)]
415415
#[note]
416-
pub(crate) struct TaitForwardCompat2 {
416+
pub struct TaitForwardCompat2 {
417417
#[primary_span]
418418
pub span: Span,
419419
#[note(hir_analysis_opaque)]

compiler/rustc_hir_analysis/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ mod coherence;
8282
mod collect;
8383
mod constrained_generic_params;
8484
mod delegation;
85-
mod errors;
85+
pub mod errors;
8686
pub mod hir_ty_lowering;
8787
pub mod hir_wf_check;
8888
mod impl_wf_check;

compiler/rustc_hir_typeck/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,13 @@ fn typeck_with_inspect<'tcx>(
247247

248248
debug!(pending_obligations = ?fcx.fulfillment_cx.borrow().pending_obligations());
249249

250+
// We need to handle opaque types before emitting ambiguity errors as applying
251+
// defining uses may guide type inference.
252+
if fcx.next_trait_solver() {
253+
fcx.handle_opaque_type_uses_next();
254+
}
255+
256+
fcx.select_obligations_where_possible(|_| {});
250257
if let None = fcx.infcx.tainted_by_errors() {
251258
fcx.report_ambiguity_errors();
252259
}

compiler/rustc_hir_typeck/src/opaque_types.rs

Lines changed: 189 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,193 @@
1-
use super::FnCtxt;
1+
use rustc_hir::def::DefKind;
2+
use rustc_hir_analysis::errors::TaitForwardCompat2;
3+
use rustc_infer::traits::ObligationCause;
4+
use rustc_middle::ty::{
5+
self, DefiningScopeKind, EarlyBinder, OpaqueHiddenType, OpaqueTypeKey, Ty, TypeVisitableExt,
6+
TypingMode,
7+
};
8+
use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
9+
use rustc_trait_selection::opaque_types::{
10+
InvalidOpaqueTypeArgs, check_opaque_type_parameter_valid,
11+
};
12+
use rustc_trait_selection::solve;
13+
use tracing::{debug, instrument};
14+
15+
use crate::FnCtxt;
16+
217
impl<'tcx> FnCtxt<'_, 'tcx> {
18+
/// This takes all the opaque type uses during HIR typeck. It first computes
19+
/// the concrete hidden type by iterating over all defining uses.
20+
///
21+
/// A use during HIR typeck is defining if all non-lifetime arguments are
22+
/// unique generic parameters and the hidden type does not reference any
23+
/// unconstrained inference variables.
24+
///
25+
/// It then uses these defining uses to guide inference for all other uses.
26+
#[instrument(level = "debug", skip(self))]
27+
pub(super) fn handle_opaque_type_uses_next(&mut self) {
28+
// We clone the opaques instead of stealing them here as they are still used for
29+
// normalization in the next generation trait solver.
30+
let mut opaque_types: Vec<_> = self.infcx.clone_opaque_types();
31+
let num_entries = self.inner.borrow_mut().opaque_types().num_entries();
32+
let prev = self.checked_opaque_types_storage_entries.replace(Some(num_entries));
33+
debug_assert_eq!(prev, None);
34+
for entry in &mut opaque_types {
35+
*entry = self.resolve_vars_if_possible(*entry);
36+
}
37+
debug!(?opaque_types);
38+
39+
self.compute_concrete_opaque_types(&opaque_types);
40+
self.apply_computed_concrete_opaque_types(&opaque_types);
41+
}
42+
43+
fn compute_concrete_opaque_types(
44+
&mut self,
45+
opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
46+
) {
47+
let tcx = self.tcx;
48+
let TypingMode::Analysis { defining_opaque_types_and_generators } = self.typing_mode()
49+
else {
50+
unreachable!();
51+
};
52+
53+
for def_id in defining_opaque_types_and_generators {
54+
match tcx.def_kind(def_id) {
55+
DefKind::OpaqueTy => {}
56+
DefKind::Closure => continue,
57+
_ => unreachable!("not opaque or generator: {def_id:?}"),
58+
}
59+
60+
let mut non_defining_use = None;
61+
let mut unconstrained_hidden_type = None;
62+
let mut found_defining_use = false;
63+
for &(opaque_type_key, hidden_type) in opaque_types {
64+
if opaque_type_key.def_id != def_id {
65+
continue;
66+
}
67+
if let Err(err) = check_opaque_type_parameter_valid(
68+
&self,
69+
opaque_type_key,
70+
hidden_type.span,
71+
DefiningScopeKind::HirTypeck,
72+
) {
73+
match err {
74+
InvalidOpaqueTypeArgs::AlreadyReported(guar) => {
75+
found_defining_use = true;
76+
self.typeck_results.borrow_mut().concrete_opaque_types.insert(
77+
opaque_type_key.def_id,
78+
OpaqueHiddenType::new_error(tcx, guar),
79+
);
80+
}
81+
_ => {
82+
non_defining_use = Some((opaque_type_key, hidden_type));
83+
}
84+
}
85+
continue;
86+
}
87+
88+
// We ignore uses of the opaque if they have any inference variables
89+
// as this can frequently happen with recursive calls.
90+
//
91+
// See `tests/ui/traits/next-solver/opaques/universal-args-non-defining.rs`.
92+
if hidden_type.ty.has_non_region_infer() {
93+
unconstrained_hidden_type = Some((opaque_type_key, hidden_type));
94+
continue;
95+
}
96+
97+
let cause = ObligationCause::misc(hidden_type.span, self.body_id);
98+
let at = self.at(&cause, self.param_env);
99+
let hidden_type = match solve::deeply_normalize(at, hidden_type) {
100+
Ok(hidden_type) => hidden_type,
101+
Err(errors) => {
102+
let guar = self.err_ctxt().report_fulfillment_errors(errors);
103+
OpaqueHiddenType::new_error(tcx, guar)
104+
}
105+
};
106+
let hidden_type = hidden_type.remap_generic_params_to_declaration_params(
107+
opaque_type_key,
108+
tcx,
109+
DefiningScopeKind::HirTypeck,
110+
);
111+
112+
found_defining_use = true;
113+
let typeck_results = &mut *self.typeck_results.borrow_mut();
114+
if let Some(prev) =
115+
typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id, hidden_type)
116+
{
117+
let entry = typeck_results
118+
.concrete_opaque_types
119+
.get_mut(&opaque_type_key.def_id)
120+
.unwrap();
121+
if prev.ty != hidden_type.ty {
122+
if let Some(guar) = self.tainted_by_errors() {
123+
entry.ty = Ty::new_error(tcx, guar);
124+
} else {
125+
let (Ok(guar) | Err(guar)) =
126+
prev.build_mismatch_error(&hidden_type, tcx).map(|d| d.emit());
127+
entry.ty = Ty::new_error(tcx, guar);
128+
}
129+
}
130+
131+
// Pick a better span if there is one.
132+
// FIXME(oli-obk): collect multiple spans for better diagnostics down the road.
133+
entry.span = prev.span.substitute_dummy(hidden_type.span);
134+
}
135+
}
136+
137+
if !found_defining_use {
138+
let guar = if let Some((_, hidden_type)) = unconstrained_hidden_type {
139+
let infer_var = hidden_type
140+
.ty
141+
.walk()
142+
.filter_map(ty::GenericArg::as_term)
143+
.find(|term| term.is_infer())
144+
.unwrap_or_else(|| hidden_type.ty.into());
145+
self.err_ctxt()
146+
.emit_inference_failure_err(
147+
self.body_id,
148+
hidden_type.span,
149+
infer_var,
150+
TypeAnnotationNeeded::E0282,
151+
false,
152+
)
153+
.emit()
154+
} else if let Some((_, hidden_type)) = non_defining_use {
155+
tcx.dcx().span_err(hidden_type.span, "non-defining use in the defining scope")
156+
} else if let Some(guar) = self.tainted_by_errors() {
157+
guar
158+
} else {
159+
self.tcx.dcx().emit_err(TaitForwardCompat2 {
160+
span: self
161+
.tcx
162+
.def_ident_span(self.body_id)
163+
.unwrap_or_else(|| self.tcx.def_span(self.body_id)),
164+
opaque_type_span: self.tcx.def_span(def_id),
165+
opaque_type: self.tcx.def_path_str(def_id),
166+
})
167+
};
168+
self.typeck_results
169+
.borrow_mut()
170+
.concrete_opaque_types
171+
.insert(def_id, OpaqueHiddenType::new_error(tcx, guar));
172+
self.set_tainted_by_errors(guar);
173+
}
174+
}
175+
}
176+
177+
fn apply_computed_concrete_opaque_types(
178+
&mut self,
179+
opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
180+
) {
181+
let tcx = self.tcx;
182+
for &(key, hidden_type) in opaque_types {
183+
let expected =
184+
*self.typeck_results.borrow_mut().concrete_opaque_types.get(&key.def_id).unwrap();
185+
186+
let expected = EarlyBinder::bind(expected.ty).instantiate(tcx, key.args);
187+
self.demand_eqtype(hidden_type.span, expected, hidden_type.ty);
188+
}
189+
}
190+
3191
/// We may in theory add further uses of an opaque after cloning the opaque
4192
/// types storage during writeback when computing the defining uses.
5193
///

compiler/rustc_hir_typeck/src/writeback.rs

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -533,8 +533,21 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
533533
}
534534
}
535535

536+
fn visit_opaque_types_next(&mut self) {
537+
let fcx_typeck_results = self.fcx.typeck_results.borrow();
538+
assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
539+
for (&def_id, &hidden_type) in &fcx_typeck_results.concrete_opaque_types {
540+
assert!(!hidden_type.has_infer());
541+
self.typeck_results.concrete_opaque_types.insert(def_id, hidden_type);
542+
}
543+
}
544+
536545
#[instrument(skip(self), level = "debug")]
537546
fn visit_opaque_types(&mut self) {
547+
if self.fcx.next_trait_solver() {
548+
return self.visit_opaque_types_next();
549+
}
550+
538551
let tcx = self.tcx();
539552
// We clone the opaques instead of stealing them here as they are still used for
540553
// normalization in the next generation trait solver.
@@ -545,14 +558,11 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
545558
for (opaque_type_key, hidden_type) in opaque_types {
546559
let hidden_type = self.resolve(hidden_type, &hidden_type.span);
547560
let opaque_type_key = self.resolve(opaque_type_key, &hidden_type.span);
548-
549-
if !self.fcx.next_trait_solver() {
550-
if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind()
551-
&& alias_ty.def_id == opaque_type_key.def_id.to_def_id()
552-
&& alias_ty.args == opaque_type_key.args
553-
{
554-
continue;
555-
}
561+
if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind()
562+
&& alias_ty.def_id == opaque_type_key.def_id.to_def_id()
563+
&& alias_ty.args == opaque_type_key.args
564+
{
565+
continue;
556566
}
557567

558568
if let Err(err) = check_opaque_type_parameter_valid(
@@ -910,6 +920,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
910920
}
911921
}
912922

923+
#[instrument(level = "debug", skip(self, outer_exclusive_binder, new_err))]
913924
fn handle_term<T>(
914925
&mut self,
915926
value: T,

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

Lines changed: 1 addition & 24 deletions
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};
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;
@@ -1128,6 +1127,7 @@ where
11281127
self.delegate.fetch_eligible_assoc_item(goal_trait_ref, trait_assoc_def_id, impl_def_id)
11291128
}
11301129

1130+
#[instrument(level = "debug", skip(self), ret)]
11311131
pub(super) fn register_hidden_type_in_storage(
11321132
&mut self,
11331133
opaque_type_key: ty::OpaqueTypeKey<I>,
@@ -1154,29 +1154,6 @@ where
11541154
self.add_goals(GoalSource::AliasWellFormed, goals);
11551155
}
11561156

1157-
// Do something for each opaque/hidden pair defined with `def_id` in the
1158-
// current inference context.
1159-
pub(super) fn probe_existing_opaque_ty(
1160-
&mut self,
1161-
key: ty::OpaqueTypeKey<I>,
1162-
) -> Option<(ty::OpaqueTypeKey<I>, I::Ty)> {
1163-
// We shouldn't have any duplicate entries when using
1164-
// this function during `TypingMode::Analysis`.
1165-
let duplicate_entries = self.delegate.clone_duplicate_opaque_types();
1166-
assert!(duplicate_entries.is_empty(), "unexpected duplicates: {duplicate_entries:?}");
1167-
let mut matching = self.delegate.clone_opaque_types_lookup_table().into_iter().filter(
1168-
|(candidate_key, _)| {
1169-
candidate_key.def_id == key.def_id
1170-
&& DeepRejectCtxt::relate_rigid_rigid(self.cx())
1171-
.args_may_unify(candidate_key.args, key.args)
1172-
},
1173-
);
1174-
let first = matching.next();
1175-
let second = matching.next();
1176-
assert_eq!(second, None);
1177-
first
1178-
}
1179-
11801157
// Try to evaluate a const, or return `None` if the const is too generic.
11811158
// This doesn't mean the const isn't evaluatable, though, and should be treated
11821159
// as an ambiguity rather than no-solution.

0 commit comments

Comments
 (0)