Skip to content

Commit f99911a

Browse files
committed
Auto merge of #55229 - nikomatsakis:issue-54692-closure-signatures, r=MatthewJasper
enforce user annotations in closure signatures Not *quite* ready yet but I'm opening anyway. Still have to finish running tests locally. Fixes #54692 Fixes #54124 r? @matthewjasper
2 parents d74b402 + 4394c83 commit f99911a

24 files changed

+321
-101
lines changed

src/librustc/ty/context.rs

+13-5
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ use ty::query;
5050
use ty::steal::Steal;
5151
use ty::BindingMode;
5252
use ty::CanonicalTy;
53-
use util::nodemap::{DefIdSet, ItemLocalMap};
53+
use ty::CanonicalPolyFnSig;
54+
use util::nodemap::{DefIdMap, DefIdSet, ItemLocalMap};
5455
use util::nodemap::{FxHashMap, FxHashSet};
5556
use smallvec::SmallVec;
5657
use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap,
@@ -344,10 +345,6 @@ pub struct TypeckTables<'tcx> {
344345
/// belongs, but it may not exist if it's a tuple field (`tuple.0`).
345346
field_indices: ItemLocalMap<usize>,
346347

347-
/// Stores the canonicalized types provided by the user. See also
348-
/// `AscribeUserType` statement in MIR.
349-
user_provided_tys: ItemLocalMap<CanonicalTy<'tcx>>,
350-
351348
/// Stores the types for various nodes in the AST. Note that this table
352349
/// is not guaranteed to be populated until after typeck. See
353350
/// typeck::check::fn_ctxt for details.
@@ -359,6 +356,14 @@ pub struct TypeckTables<'tcx> {
359356
/// other items.
360357
node_substs: ItemLocalMap<&'tcx Substs<'tcx>>,
361358

359+
/// Stores the canonicalized types provided by the user. See also
360+
/// `AscribeUserType` statement in MIR.
361+
user_provided_tys: ItemLocalMap<CanonicalTy<'tcx>>,
362+
363+
/// Stores the canonicalized types provided by the user. See also
364+
/// `AscribeUserType` statement in MIR.
365+
pub user_provided_sigs: DefIdMap<CanonicalPolyFnSig<'tcx>>,
366+
362367
/// Stores the substitutions that the user explicitly gave (if any)
363368
/// attached to `id`. These will not include any inferred
364369
/// values. The canonical form is used to capture things like `_`
@@ -442,6 +447,7 @@ impl<'tcx> TypeckTables<'tcx> {
442447
type_dependent_defs: ItemLocalMap(),
443448
field_indices: ItemLocalMap(),
444449
user_provided_tys: ItemLocalMap(),
450+
user_provided_sigs: Default::default(),
445451
node_types: ItemLocalMap(),
446452
node_substs: ItemLocalMap(),
447453
user_substs: ItemLocalMap(),
@@ -748,6 +754,7 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
748754
ref type_dependent_defs,
749755
ref field_indices,
750756
ref user_provided_tys,
757+
ref user_provided_sigs,
751758
ref node_types,
752759
ref node_substs,
753760
ref user_substs,
@@ -771,6 +778,7 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
771778
type_dependent_defs.hash_stable(hcx, hasher);
772779
field_indices.hash_stable(hcx, hasher);
773780
user_provided_tys.hash_stable(hcx, hasher);
781+
user_provided_sigs.hash_stable(hcx, hasher);
774782
node_types.hash_stable(hcx, hasher);
775783
node_substs.hash_stable(hcx, hasher);
776784
user_substs.hash_stable(hcx, hasher);

src/librustc/ty/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
6464
use hir;
6565

6666
pub use self::sty::{Binder, BoundTy, BoundTyIndex, DebruijnIndex, INNERMOST};
67-
pub use self::sty::{FnSig, GenSig, PolyFnSig, PolyGenSig};
67+
pub use self::sty::{FnSig, GenSig, CanonicalPolyFnSig, PolyFnSig, PolyGenSig};
6868
pub use self::sty::{InferTy, ParamTy, ProjectionTy, ExistentialPredicate};
6969
pub use self::sty::{ClosureSubsts, GeneratorSubsts, UpvarSubsts, TypeAndMut};
7070
pub use self::sty::{TraitRef, TyKind, PolyTraitRef};

src/librustc/ty/sty.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
//! This module contains TyKind and its major components
1212
1313
use hir::def_id::DefId;
14-
14+
use infer::canonical::Canonical;
1515
use mir::interpret::ConstValue;
1616
use middle::region;
1717
use polonius_engine::Atom;
@@ -980,6 +980,9 @@ impl<'tcx> PolyFnSig<'tcx> {
980980
}
981981
}
982982

983+
pub type CanonicalPolyFnSig<'tcx> = Canonical<'tcx, Binder<FnSig<'tcx>>>;
984+
985+
983986
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
984987
pub struct ParamTy {
985988
pub idx: u32,

src/librustc_mir/borrow_check/nll/region_infer/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1208,6 +1208,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
12081208
// to report the error. This gives better error messages
12091209
// in some cases.
12101210
self.report_error(mir, infcx, mir_def_id, longer_fr, shorter_fr, errors_buffer);
1211+
return; // continuing to iterate just reports more errors than necessary
12111212
}
12121213
}
12131214

src/librustc_mir/borrow_check/nll/type_check/input_output.rs

+74-2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
//! contain revealed `impl Trait` values).
1919
2020
use borrow_check::nll::universal_regions::UniversalRegions;
21+
use rustc::infer::LateBoundRegionConversionTime;
2122
use rustc::mir::*;
2223
use rustc::ty::Ty;
2324

@@ -36,9 +37,47 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
3637
let (&normalized_output_ty, normalized_input_tys) =
3738
normalized_inputs_and_output.split_last().unwrap();
3839

40+
// If the user explicitly annotated the input types, extract
41+
// those.
42+
//
43+
// e.g. `|x: FxHashMap<_, &'static u32>| ...`
44+
let user_provided_sig;
45+
if !self.tcx().is_closure(self.mir_def_id) {
46+
user_provided_sig = None;
47+
} else {
48+
let typeck_tables = self.tcx().typeck_tables_of(self.mir_def_id);
49+
user_provided_sig = match typeck_tables.user_provided_sigs.get(&self.mir_def_id) {
50+
None => None,
51+
Some(user_provided_poly_sig) => {
52+
// Instantiate the canonicalized variables from
53+
// user-provided signature (e.g. the `_` in the code
54+
// above) with fresh variables.
55+
let (poly_sig, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars(
56+
mir.span,
57+
&user_provided_poly_sig,
58+
);
59+
60+
// Replace the bound items in the fn sig with fresh
61+
// variables, so that they represent the view from
62+
// "inside" the closure.
63+
Some(
64+
self.infcx
65+
.replace_late_bound_regions_with_fresh_var(
66+
mir.span,
67+
LateBoundRegionConversionTime::FnCall,
68+
&poly_sig,
69+
)
70+
.0,
71+
)
72+
}
73+
}
74+
};
75+
3976
// Equate expected input tys with those in the MIR.
40-
let argument_locals = (1..).map(Local::new);
41-
for (&normalized_input_ty, local) in normalized_input_tys.iter().zip(argument_locals) {
77+
for (&normalized_input_ty, argument_index) in normalized_input_tys.iter().zip(0..) {
78+
// In MIR, argument N is stored in local N+1.
79+
let local = Local::new(argument_index + 1);
80+
4281
debug!(
4382
"equate_inputs_and_outputs: normalized_input_ty = {:?}",
4483
normalized_input_ty
@@ -53,6 +92,27 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
5392
);
5493
}
5594

95+
if let Some(user_provided_sig) = user_provided_sig {
96+
for (&user_provided_input_ty, argument_index) in
97+
user_provided_sig.inputs().iter().zip(0..)
98+
{
99+
// In MIR, closures begin an implicit `self`, so
100+
// argument N is stored in local N+2.
101+
let local = Local::new(argument_index + 2);
102+
let mir_input_ty = mir.local_decls[local].ty;
103+
let mir_input_span = mir.local_decls[local].source_info.span;
104+
105+
// If the user explicitly annotated the input types, enforce those.
106+
let user_provided_input_ty =
107+
self.normalize(user_provided_input_ty, Locations::All(mir_input_span));
108+
self.equate_normalized_input_or_output(
109+
user_provided_input_ty,
110+
mir_input_ty,
111+
mir_input_span,
112+
);
113+
}
114+
}
115+
56116
assert!(
57117
mir.yield_ty.is_some() && universal_regions.yield_ty.is_some()
58118
|| mir.yield_ty.is_none() && universal_regions.yield_ty.is_none()
@@ -83,6 +143,18 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
83143
terr
84144
);
85145
};
146+
147+
// If the user explicitly annotated the output types, enforce those.
148+
if let Some(user_provided_sig) = user_provided_sig {
149+
let user_provided_output_ty = user_provided_sig.output();
150+
let user_provided_output_ty =
151+
self.normalize(user_provided_output_ty, Locations::All(output_span));
152+
self.equate_normalized_input_or_output(
153+
user_provided_output_ty,
154+
mir_output_ty,
155+
output_span,
156+
);
157+
}
86158
}
87159

88160
fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) {

src/librustc_mir/borrow_check/nll/type_check/mod.rs

+28-23
Original file line numberDiff line numberDiff line change
@@ -1033,6 +1033,12 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
10331033
assert!(!impl_self_ty.has_infer_types());
10341034

10351035
self.eq_types(self_ty, impl_self_ty, locations, category)?;
1036+
1037+
self.prove_predicate(
1038+
ty::Predicate::WellFormed(impl_self_ty),
1039+
locations,
1040+
category,
1041+
);
10361042
}
10371043

10381044
// Prove the predicates coming along with `def_id`.
@@ -1070,11 +1076,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
10701076
/// particularly necessary -- we'll do it lazilly as we process
10711077
/// the value anyway -- but in some specific cases it is useful to
10721078
/// normalize so we can suppress duplicate error messages.
1073-
fn fold_to_region_vid<T>(
1074-
&self,
1075-
value: T
1076-
) -> T
1077-
where T: TypeFoldable<'tcx>
1079+
fn fold_to_region_vid<T>(&self, value: T) -> T
1080+
where
1081+
T: TypeFoldable<'tcx>,
10781082
{
10791083
if let Some(borrowck_context) = &self.borrowck_context {
10801084
self.tcx().fold_regions(&value, &mut false, |r, _debruijn| {
@@ -1210,20 +1214,22 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
12101214
// though.
12111215
let category = match *place {
12121216
Place::Local(RETURN_PLACE) => if let Some(BorrowCheckContext {
1213-
universal_regions: UniversalRegions {
1214-
defining_ty: DefiningTy::Const(def_id, _),
1215-
..
1216-
},
1217+
universal_regions:
1218+
UniversalRegions {
1219+
defining_ty: DefiningTy::Const(def_id, _),
1220+
..
1221+
},
12171222
..
1218-
}) = self.borrowck_context {
1223+
}) = self.borrowck_context
1224+
{
12191225
if tcx.is_static(*def_id).is_some() {
12201226
ConstraintCategory::UseAsStatic
12211227
} else {
12221228
ConstraintCategory::UseAsConst
12231229
}
12241230
} else {
12251231
ConstraintCategory::Return
1226-
}
1232+
},
12271233
Place::Local(l) if !mir.local_decls[l].is_user_variable.is_some() => {
12281234
ConstraintCategory::Boring
12291235
}
@@ -1510,12 +1516,14 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
15101516
let category = match *dest {
15111517
Place::Local(RETURN_PLACE) => {
15121518
if let Some(BorrowCheckContext {
1513-
universal_regions: UniversalRegions {
1514-
defining_ty: DefiningTy::Const(def_id, _),
1515-
..
1516-
},
1519+
universal_regions:
1520+
UniversalRegions {
1521+
defining_ty: DefiningTy::Const(def_id, _),
1522+
..
1523+
},
15171524
..
1518-
}) = self.borrowck_context {
1525+
}) = self.borrowck_context
1526+
{
15191527
if tcx.is_static(*def_id).is_some() {
15201528
ConstraintCategory::UseAsStatic
15211529
} else {
@@ -1524,7 +1532,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
15241532
} else {
15251533
ConstraintCategory::Return
15261534
}
1527-
},
1535+
}
15281536
Place::Local(l) if !mir.local_decls[l].is_user_variable.is_some() => {
15291537
ConstraintCategory::Boring
15301538
}
@@ -1582,12 +1590,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
15821590
} else {
15831591
ConstraintCategory::Boring
15841592
};
1585-
if let Err(terr) = self.sub_types(
1586-
op_arg_ty,
1587-
fn_arg,
1588-
term_location.to_locations(),
1589-
category,
1590-
) {
1593+
if let Err(terr) =
1594+
self.sub_types(op_arg_ty, fn_arg, term_location.to_locations(), category)
1595+
{
15911596
span_mirbug!(
15921597
self,
15931598
term,

src/librustc_typeck/check/closure.rs

+17-4
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
377377
) -> ClosureSignatures<'tcx> {
378378
debug!("sig_of_closure_no_expectation()");
379379

380-
let bound_sig = self.supplied_sig_of_closure(decl);
380+
let bound_sig = self.supplied_sig_of_closure(expr_def_id, decl);
381381

382382
self.closure_sigs(expr_def_id, body, bound_sig)
383383
}
@@ -479,7 +479,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
479479
// Along the way, it also writes out entries for types that the user
480480
// wrote into our tables, which are then later used by the privacy
481481
// check.
482-
match self.check_supplied_sig_against_expectation(decl, &closure_sigs) {
482+
match self.check_supplied_sig_against_expectation(expr_def_id, decl, &closure_sigs) {
483483
Ok(infer_ok) => self.register_infer_ok_obligations(infer_ok),
484484
Err(_) => return self.sig_of_closure_no_expectation(expr_def_id, decl, body),
485485
}
@@ -521,14 +521,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
521521
/// strategy.
522522
fn check_supplied_sig_against_expectation(
523523
&self,
524+
expr_def_id: DefId,
524525
decl: &hir::FnDecl,
525526
expected_sigs: &ClosureSignatures<'tcx>,
526527
) -> InferResult<'tcx, ()> {
527528
// Get the signature S that the user gave.
528529
//
529530
// (See comment on `sig_of_closure_with_expectation` for the
530531
// meaning of these letters.)
531-
let supplied_sig = self.supplied_sig_of_closure(decl);
532+
let supplied_sig = self.supplied_sig_of_closure(expr_def_id, decl);
532533

533534
debug!(
534535
"check_supplied_sig_against_expectation: supplied_sig={:?}",
@@ -598,7 +599,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
598599

599600
/// If there is no expected signature, then we will convert the
600601
/// types that the user gave into a signature.
601-
fn supplied_sig_of_closure(&self, decl: &hir::FnDecl) -> ty::PolyFnSig<'tcx> {
602+
///
603+
/// Also, record this closure signature for later.
604+
fn supplied_sig_of_closure(
605+
&self,
606+
expr_def_id: DefId,
607+
decl: &hir::FnDecl,
608+
) -> ty::PolyFnSig<'tcx> {
602609
let astconv: &dyn AstConv = self;
603610

604611
// First, convert the types that the user supplied (if any).
@@ -618,6 +625,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
618625

619626
debug!("supplied_sig_of_closure: result={:?}", result);
620627

628+
let c_result = self.inh.infcx.canonicalize_response(&result);
629+
self.tables.borrow_mut().user_provided_sigs.insert(
630+
expr_def_id,
631+
c_result,
632+
);
633+
621634
result
622635
}
623636

0 commit comments

Comments
 (0)