Auto merge of #55229 - nikomatsakis:issue-54692-closure-signatures, r… · rust-lang/rust@f99911a (original) (raw)

24 files changed

lines changed

Original file line number Diff line number Diff line change
@@ -50,7 +50,8 @@ use ty::query;
50 50 use ty::steal::Steal;
51 51 use ty::BindingMode;
52 52 use ty::CanonicalTy;
53 -use util::nodemap::{DefIdSet, ItemLocalMap};
53 +use ty::CanonicalPolyFnSig;
54 +use util::nodemap::{DefIdMap, DefIdSet, ItemLocalMap};
54 55 use util::nodemap::{FxHashMap, FxHashSet};
55 56 use smallvec::SmallVec;
56 57 use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap,
@@ -344,10 +345,6 @@ pub struct TypeckTables<'tcx> {
344 345 /// belongs, but it may not exist if it's a tuple field (`tuple.0`).
345 346 field_indices: ItemLocalMap<usize>,
346 347
347 -/// Stores the canonicalized types provided by the user. See also
348 - /// `AscribeUserType` statement in MIR.
349 - user_provided_tys: ItemLocalMap<CanonicalTy<'tcx>>,
350 -
351 348 /// Stores the types for various nodes in the AST. Note that this table
352 349 /// is not guaranteed to be populated until after typeck. See
353 350 /// typeck::check::fn_ctxt for details.
@@ -359,6 +356,14 @@ pub struct TypeckTables<'tcx> {
359 356 /// other items.
360 357 node_substs: ItemLocalMap<&'tcx Substs<'tcx>>,
361 358
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 +
362 367 /// Stores the substitutions that the user explicitly gave (if any)
363 368 /// attached to `id`. These will not include any inferred
364 369 /// values. The canonical form is used to capture things like `_`
@@ -442,6 +447,7 @@ impl<'tcx> TypeckTables<'tcx> {
442 447 type_dependent_defs: ItemLocalMap(),
443 448 field_indices: ItemLocalMap(),
444 449 user_provided_tys: ItemLocalMap(),
450 +user_provided_sigs: Default::default(),
445 451 node_types: ItemLocalMap(),
446 452 node_substs: ItemLocalMap(),
447 453 user_substs: ItemLocalMap(),
@@ -748,6 +754,7 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
748 754 ref type_dependent_defs,
749 755 ref field_indices,
750 756 ref user_provided_tys,
757 +ref user_provided_sigs,
751 758 ref node_types,
752 759 ref node_substs,
753 760 ref user_substs,
@@ -771,6 +778,7 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
771 778 type_dependent_defs.hash_stable(hcx, hasher);
772 779 field_indices.hash_stable(hcx, hasher);
773 780 user_provided_tys.hash_stable(hcx, hasher);
781 + user_provided_sigs.hash_stable(hcx, hasher);
774 782 node_types.hash_stable(hcx, hasher);
775 783 node_substs.hash_stable(hcx, hasher);
776 784 user_substs.hash_stable(hcx, hasher);
Original file line number Diff line number Diff line change
@@ -64,7 +64,7 @@ use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
64 64 use hir;
65 65
66 66 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};
68 68 pub use self::sty::{InferTy, ParamTy, ProjectionTy, ExistentialPredicate};
69 69 pub use self::sty::{ClosureSubsts, GeneratorSubsts, UpvarSubsts, TypeAndMut};
70 70 pub use self::sty::{TraitRef, TyKind, PolyTraitRef};
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@
11 11 //! This module contains TyKind and its major components
12 12
13 13 use hir::def_id::DefId;
14 -
14 +use infer::canonical::Canonical;
15 15 use mir::interpret::ConstValue;
16 16 use middle::region;
17 17 use polonius_engine::Atom;
@@ -980,6 +980,9 @@ impl<'tcx> PolyFnSig<'tcx> {
980 980 }
981 981 }
982 982
983 +pub type CanonicalPolyFnSig<'tcx> = Canonical<'tcx, Binder<FnSig<'tcx>>>;
984 +
985 +
983 986 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
984 987 pub struct ParamTy {
985 988 pub idx: u32,
Original file line number Diff line number Diff line change
@@ -1208,6 +1208,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
1208 1208 // to report the error. This gives better error messages
1209 1209 // in some cases.
1210 1210 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
1211 1212 }
1212 1213 }
1213 1214
Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@
18 18 //! contain revealed `impl Trait` values).
19 19
20 20 use borrow_check::nll::universal_regions::UniversalRegions;
21 +use rustc::infer::LateBoundRegionConversionTime;
21 22 use rustc::mir::*;
22 23 use rustc::ty::Ty;
23 24
@@ -36,9 +37,47 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
36 37 let (&normalized_output_ty, normalized_input_tys) =
37 38 normalized_inputs_and_output.split_last().unwrap();
38 39
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 +
39 76 // 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 +
42 81 debug!(
43 82 "equate_inputs_and_outputs: normalized_input_ty = {:?}",
44 83 normalized_input_ty
@@ -53,6 +92,27 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
53 92 );
54 93 }
55 94
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 +
56 116 assert!(
57 117 mir.yield_ty.is_some() && universal_regions.yield_ty.is_some()
58 118 |
@@ -83,6 +143,18 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
83 143 terr
84 144 );
85 145 };
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 +}
86 158 }
87 159
88 160 fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) {
Original file line number Diff line number Diff line change
@@ -1033,6 +1033,12 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
1033 1033 assert!(!impl_self_ty.has_infer_types());
1034 1034
1035 1035 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 +);
1036 1042 }
1037 1043
1038 1044 // Prove the predicates coming along with `def_id`.
@@ -1070,11 +1076,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
1070 1076 /// particularly necessary -- we'll do it lazilly as we process
1071 1077 /// the value anyway -- but in some specific cases it is useful to
1072 1078 /// 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>,
1078 1082 {
1079 1083 if let Some(borrowck_context) = &self.borrowck_context {
1080 1084 self.tcx().fold_regions(&value, &mut false, |r, _debruijn
@@ -1210,20 +1214,22 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
1210 1214 // though.
1211 1215 let category = match *place {
1212 1216 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 +},
1217 1222 ..
1218 -}) = self.borrowck_context {
1223 +}) = self.borrowck_context
1224 +{
1219 1225 if tcx.is_static(*def_id).is_some() {
1220 1226 ConstraintCategory::UseAsStatic
1221 1227 } else {
1222 1228 ConstraintCategory::UseAsConst
1223 1229 }
1224 1230 } else {
1225 1231 ConstraintCategory::Return
1226 -}
1232 +},
1227 1233 Place::Local(l) if !mir.local_decls[l].is_user_variable.is_some() => {
1228 1234 ConstraintCategory::Boring
1229 1235 }
@@ -1510,12 +1516,14 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
1510 1516 let category = match *dest {
1511 1517 Place::Local(RETURN_PLACE) => {
1512 1518 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 +},
1517 1524 ..
1518 -}) = self.borrowck_context {
1525 +}) = self.borrowck_context
1526 +{
1519 1527 if tcx.is_static(*def_id).is_some() {
1520 1528 ConstraintCategory::UseAsStatic
1521 1529 } else {
@@ -1524,7 +1532,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
1524 1532 } else {
1525 1533 ConstraintCategory::Return
1526 1534 }
1527 -},
1535 +}
1528 1536 Place::Local(l) if !mir.local_decls[l].is_user_variable.is_some() => {
1529 1537 ConstraintCategory::Boring
1530 1538 }
@@ -1582,12 +1590,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
1582 1590 } else {
1583 1591 ConstraintCategory::Boring
1584 1592 };
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 +{
1591 1596 span_mirbug!(
1592 1597 self,
1593 1598 term,
Original file line number Diff line number Diff line change
@@ -377,7 +377,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
377 377 ) -> ClosureSignatures<'tcx> {
378 378 debug!("sig_of_closure_no_expectation()");
379 379
380 -let bound_sig = self.supplied_sig_of_closure(decl);
380 +let bound_sig = self.supplied_sig_of_closure(expr_def_id, decl);
381 381
382 382 self.closure_sigs(expr_def_id, body, bound_sig)
383 383 }
@@ -479,7 +479,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
479 479 // Along the way, it also writes out entries for types that the user
480 480 // wrote into our tables, which are then later used by the privacy
481 481 // 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) {
483 483 Ok(infer_ok) => self.register_infer_ok_obligations(infer_ok),
484 484 Err(_) => return self.sig_of_closure_no_expectation(expr_def_id, decl, body),
485 485 }
@@ -521,14 +521,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
521 521 /// strategy.
522 522 fn check_supplied_sig_against_expectation(
523 523 &self,
524 +expr_def_id: DefId,
524 525 decl: &hir::FnDecl,
525 526 expected_sigs: &ClosureSignatures<'tcx>,
526 527 ) -> InferResult<'tcx, ()> {
527 528 // Get the signature S that the user gave.
528 529 //
529 530 // (See comment on `sig_of_closure_with_expectation` for the
530 531 // 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);
532 533
533 534 debug!(
534 535 "check_supplied_sig_against_expectation: supplied_sig={:?}",
@@ -598,7 +599,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
598 599
599 600 /// If there is no expected signature, then we will convert the
600 601 /// 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> {
602 609 let astconv: &dyn AstConv = self;
603 610
604 611 // First, convert the types that the user supplied (if any).
@@ -618,6 +625,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
618 625
619 626 debug!("supplied_sig_of_closure: result={:?}", result);
620 627
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 +
621 634 result
622 635 }
623 636