Skip to content

Commit 3830827

Browse files
authored
Rollup merge of rust-lang#88312 - jackh726:issue-87748, r=nikomatsakis
Treat types in unnormalized function signatures as well-formed Fixes rust-lang#87748 r? ```@nikomatsakis```
2 parents b33f35a + 97bf80d commit 3830827

File tree

6 files changed

+90
-9
lines changed

6 files changed

+90
-9
lines changed

compiler/rustc_mir/src/borrow_check/type_check/free_region_relations.rs

+17-2
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,9 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> {
256256
let constraint_sets: Vec<_> = unnormalized_input_output_tys
257257
.flat_map(|ty| {
258258
debug!("build: input_or_output={:?}", ty);
259+
// We add implied bounds from both the unnormalized and normalized ty
260+
// See issue #87748
261+
let constraints_implied_1 = self.add_implied_bounds(ty);
259262
let TypeOpOutput { output: ty, constraints: constraints1, .. } = self
260263
.param_env
261264
.and(type_op::normalize::Normalize::new(ty))
@@ -271,9 +274,21 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> {
271274
canonicalized_query: None,
272275
}
273276
});
274-
let constraints2 = self.add_implied_bounds(ty);
277+
// Note: we need this in examples like
278+
// ```
279+
// trait Foo {
280+
// type Bar;
281+
// fn foo(&self) -> &Self::Bar;
282+
// }
283+
// impl Foo for () {
284+
// type Bar = ();
285+
// fn foo(&self) ->&() {}
286+
// }
287+
// ```
288+
// Both &Self::Bar and &() are WF
289+
let constraints_implied_2 = self.add_implied_bounds(ty);
275290
normalized_inputs_and_output.push(ty);
276-
constraints1.into_iter().chain(constraints2)
291+
constraints1.into_iter().chain(constraints_implied_1).chain(constraints_implied_2)
277292
})
278293
.collect();
279294

compiler/rustc_typeck/src/check/compare_method.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,8 @@ fn compare_predicate_entailment<'tcx>(
250250
// Compute placeholder form of impl and trait method tys.
251251
let tcx = infcx.tcx;
252252

253+
let mut wf_tys = vec![];
254+
253255
let (impl_sig, _) = infcx.replace_bound_vars_with_fresh_vars(
254256
impl_m_span,
255257
infer::HigherRankedType,
@@ -260,10 +262,18 @@ fn compare_predicate_entailment<'tcx>(
260262
let impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig));
261263
debug!("compare_impl_method: impl_fty={:?}", impl_fty);
262264

265+
// First liberate late bound regions and subst placeholders
263266
let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, tcx.fn_sig(trait_m.def_id));
264267
let trait_sig = trait_sig.subst(tcx, trait_to_placeholder_substs);
268+
// Next, add all inputs and output as well-formed tys. Importantly,
269+
// we have to do this before normalization, since the normalized ty may
270+
// not contain the input parameters. See issue #87748.
271+
wf_tys.extend(trait_sig.inputs_and_output.iter());
265272
let trait_sig =
266273
inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, trait_sig);
274+
// Also add the resulting inputs and output as well-formed.
275+
// This probably isn't strictly necessary.
276+
wf_tys.extend(trait_sig.inputs_and_output.iter());
267277
let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig));
268278

269279
debug!("compare_impl_method: trait_fty={:?}", trait_fty);
@@ -388,7 +398,7 @@ fn compare_predicate_entailment<'tcx>(
388398
// Finally, resolve all regions. This catches wily misuses of
389399
// lifetime parameters.
390400
let fcx = FnCtxt::new(&inh, param_env, impl_m_hir_id);
391-
fcx.regionck_item(impl_m_hir_id, impl_m_span, trait_sig.inputs_and_output);
401+
fcx.regionck_item(impl_m_hir_id, impl_m_span, &wf_tys);
392402

393403
Ok(())
394404
})

compiler/rustc_typeck/src/check/mod.rs

+12-4
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ fn typeck_with_fallback<'tcx>(
364364

365365
let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
366366
let param_env = tcx.param_env(def_id);
367-
let fcx = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
367+
let (fcx, wf_tys) = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
368368
let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() {
369369
let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
370370
<dyn AstConv<'_>>::ty_of_fn(
@@ -383,17 +383,25 @@ fn typeck_with_fallback<'tcx>(
383383

384384
check_abi(tcx, id, span, fn_sig.abi());
385385

386+
// When normalizing the function signature, we assume all types are
387+
// well-formed. So, we don't need to worry about the obligations
388+
// from normalization. We could just discard these, but to align with
389+
// compare_method and elsewhere, we just add implied bounds for
390+
// these types.
391+
let mut wf_tys = vec![];
386392
// Compute the fty from point of view of inside the fn.
387393
let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
394+
wf_tys.extend(fn_sig.inputs_and_output.iter());
388395
let fn_sig = inh.normalize_associated_types_in(
389396
body.value.span,
390397
body_id.hir_id,
391398
param_env,
392399
fn_sig,
393400
);
401+
wf_tys.extend(fn_sig.inputs_and_output.iter());
394402

395403
let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0;
396-
fcx
404+
(fcx, wf_tys)
397405
} else {
398406
let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
399407
let expected_type = body_ty
@@ -443,7 +451,7 @@ fn typeck_with_fallback<'tcx>(
443451

444452
fcx.write_ty(id, expected_type);
445453

446-
fcx
454+
(fcx, vec![])
447455
};
448456

449457
let fallback_has_occurred = fcx.type_inference_fallback();
@@ -467,7 +475,7 @@ fn typeck_with_fallback<'tcx>(
467475
fcx.select_all_obligations_or_error();
468476

469477
if fn_sig.is_some() {
470-
fcx.regionck_fn(id, body);
478+
fcx.regionck_fn(id, body, span, &wf_tys);
471479
} else {
472480
fcx.regionck_expr(body);
473481
}

compiler/rustc_typeck/src/check/regionck.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -144,11 +144,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
144144
/// rest of type check and because sometimes we need type
145145
/// inference to have completed before we can determine which
146146
/// constraints to add.
147-
pub fn regionck_fn(&self, fn_id: hir::HirId, body: &'tcx hir::Body<'tcx>) {
147+
pub(crate) fn regionck_fn(
148+
&self,
149+
fn_id: hir::HirId,
150+
body: &'tcx hir::Body<'tcx>,
151+
span: Span,
152+
wf_tys: &[Ty<'tcx>],
153+
) {
148154
debug!("regionck_fn(id={})", fn_id);
149155
let subject = self.tcx.hir().body_owner_def_id(body.id());
150156
let hir_id = body.value.hir_id;
151157
let mut rcx = RegionCtxt::new(self, hir_id, Subject(subject), self.param_env);
158+
// We need to add the implied bounds from the function signature
159+
rcx.outlives_environment.add_implied_bounds(self, wf_tys, fn_id, span);
160+
rcx.outlives_environment.save_implied_bounds(fn_id);
152161

153162
if !self.errors_reported_since_creation() {
154163
// regionck assumes typeck succeeded

compiler/rustc_typeck/src/check/wfcheck.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,7 @@ fn check_where_clauses<'tcx, 'fcx>(
911911
}
912912
}
913913

914+
#[tracing::instrument(level = "debug", skip(fcx, span, hir_decl))]
914915
fn check_fn_or_method<'fcx, 'tcx>(
915916
fcx: &FnCtxt<'fcx, 'tcx>,
916917
span: Span,
@@ -921,6 +922,11 @@ fn check_fn_or_method<'fcx, 'tcx>(
921922
) {
922923
let sig = fcx.tcx.liberate_late_bound_regions(def_id, sig);
923924

925+
// Unnormalized types in signature are WF too
926+
implied_bounds.extend(sig.inputs());
927+
// FIXME(#27579) return types should not be implied bounds
928+
implied_bounds.push(sig.output());
929+
924930
// Normalize the input and output types one at a time, using a different
925931
// `WellFormedLoc` for each. We cannot call `normalize_associated_types`
926932
// on the entire `FnSig`, since this would use the same `WellFormedLoc`
@@ -970,9 +976,11 @@ fn check_fn_or_method<'fcx, 'tcx>(
970976
ObligationCauseCode::ReturnType,
971977
);
972978

973-
// FIXME(#25759) return types should not be implied bounds
979+
// FIXME(#27579) return types should not be implied bounds
974980
implied_bounds.push(sig.output());
975981

982+
debug!(?implied_bounds);
983+
976984
check_where_clauses(fcx, span, def_id, Some((sig.output(), hir_decl.output.span())));
977985
}
978986

@@ -1117,6 +1125,7 @@ const HELP_FOR_SELF_TYPE: &str = "consider changing to `self`, `&self`, `&mut se
11171125
`self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one \
11181126
of the previous types except `Self`)";
11191127

1128+
#[tracing::instrument(level = "debug", skip(fcx))]
11201129
fn check_method_receiver<'fcx, 'tcx>(
11211130
fcx: &FnCtxt<'fcx, 'tcx>,
11221131
fn_sig: &hir::FnSig<'_>,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Checks that we properly add implied bounds from unnormalized projections in
2+
// inputs when typechecking functions.
3+
4+
// check-pass
5+
6+
#![feature(generic_associated_types)]
7+
8+
trait MyTrait {
9+
type Assoc<'a, 'b> where 'b: 'a;
10+
fn do_sth(arg: Self::Assoc<'_, '_>);
11+
}
12+
13+
struct A;
14+
struct B;
15+
struct C;
16+
17+
impl MyTrait for A {
18+
type Assoc<'a, 'b> where 'b: 'a = u32;
19+
fn do_sth(_: u32) {}
20+
}
21+
impl MyTrait for B {
22+
type Assoc<'a, 'b> where 'b: 'a = u32;
23+
fn do_sth(_: Self::Assoc<'_, '_>) {}
24+
}
25+
impl MyTrait for C {
26+
type Assoc<'a, 'b> where 'b: 'a = u32;
27+
fn do_sth(_: Self::Assoc<'static, 'static>) {}
28+
}
29+
30+
fn main () {}

0 commit comments

Comments
 (0)