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 |