diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 3ee034cb09e..e2f27074dbf 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -61,95 +61,95 @@ pub struct CombineFields<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { } impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { -pub fn super_combine_tys(&self, - relation: &mut R, - a: Ty<'tcx>, - b: Ty<'tcx>) + pub fn super_combine_tys(&self, + relation: &mut R, + a: Ty<'tcx>, + b: Ty<'tcx>) + -> RelateResult<'tcx, Ty<'tcx>> + where R: TypeRelation<'a, 'gcx, 'tcx> + { + let a_is_expected = relation.a_is_expected(); + + match (&a.sty, &b.sty) { + // Relate integral variables to other types + (&ty::TyInfer(ty::IntVar(a_id)), &ty::TyInfer(ty::IntVar(b_id))) => { + self.int_unification_table + .borrow_mut() + .unify_var_var(a_id, b_id) + .map_err(|e| int_unification_error(a_is_expected, e))?; + Ok(a) + } + (&ty::TyInfer(ty::IntVar(v_id)), &ty::TyInt(v)) => { + self.unify_integral_variable(a_is_expected, v_id, IntType(v)) + } + (&ty::TyInt(v), &ty::TyInfer(ty::IntVar(v_id))) => { + self.unify_integral_variable(!a_is_expected, v_id, IntType(v)) + } + (&ty::TyInfer(ty::IntVar(v_id)), &ty::TyUint(v)) => { + self.unify_integral_variable(a_is_expected, v_id, UintType(v)) + } + (&ty::TyUint(v), &ty::TyInfer(ty::IntVar(v_id))) => { + self.unify_integral_variable(!a_is_expected, v_id, UintType(v)) + } + + // Relate floating-point variables to other types + (&ty::TyInfer(ty::FloatVar(a_id)), &ty::TyInfer(ty::FloatVar(b_id))) => { + self.float_unification_table + .borrow_mut() + .unify_var_var(a_id, b_id) + .map_err(|e| float_unification_error(relation.a_is_expected(), e))?; + Ok(a) + } + (&ty::TyInfer(ty::FloatVar(v_id)), &ty::TyFloat(v)) => { + self.unify_float_variable(a_is_expected, v_id, v) + } + (&ty::TyFloat(v), &ty::TyInfer(ty::FloatVar(v_id))) => { + self.unify_float_variable(!a_is_expected, v_id, v) + } + + // All other cases of inference are errors + (&ty::TyInfer(_), _) | + (_, &ty::TyInfer(_)) => { + Err(TypeError::Sorts(ty::relate::expected_found(relation, &a, &b))) + } + + + _ => { + ty::relate::super_relate_tys(relation, a, b) + } + } + } + + fn unify_integral_variable(&self, + vid_is_expected: bool, + vid: ty::IntVid, + val: ty::IntVarValue) + -> RelateResult<'tcx, Ty<'tcx>> + { + self.int_unification_table + .borrow_mut() + .unify_var_value(vid, val) + .map_err(|e| int_unification_error(vid_is_expected, e))?; + match val { + IntType(v) => Ok(self.tcx.mk_mach_int(v)), + UintType(v) => Ok(self.tcx.mk_mach_uint(v)), + } + } + + fn unify_float_variable(&self, + vid_is_expected: bool, + vid: ty::FloatVid, + val: ast::FloatTy) -> RelateResult<'tcx, Ty<'tcx>> - where R: TypeRelation<'a, 'gcx, 'tcx> -{ - let a_is_expected = relation.a_is_expected(); - - match (&a.sty, &b.sty) { - // Relate integral variables to other types - (&ty::TyInfer(ty::IntVar(a_id)), &ty::TyInfer(ty::IntVar(b_id))) => { - self.int_unification_table - .borrow_mut() - .unify_var_var(a_id, b_id) - .map_err(|e| int_unification_error(a_is_expected, e))?; - Ok(a) - } - (&ty::TyInfer(ty::IntVar(v_id)), &ty::TyInt(v)) => { - self.unify_integral_variable(a_is_expected, v_id, IntType(v)) - } - (&ty::TyInt(v), &ty::TyInfer(ty::IntVar(v_id))) => { - self.unify_integral_variable(!a_is_expected, v_id, IntType(v)) - } - (&ty::TyInfer(ty::IntVar(v_id)), &ty::TyUint(v)) => { - self.unify_integral_variable(a_is_expected, v_id, UintType(v)) - } - (&ty::TyUint(v), &ty::TyInfer(ty::IntVar(v_id))) => { - self.unify_integral_variable(!a_is_expected, v_id, UintType(v)) - } - - // Relate floating-point variables to other types - (&ty::TyInfer(ty::FloatVar(a_id)), &ty::TyInfer(ty::FloatVar(b_id))) => { - self.float_unification_table - .borrow_mut() - .unify_var_var(a_id, b_id) - .map_err(|e| float_unification_error(relation.a_is_expected(), e))?; - Ok(a) - } - (&ty::TyInfer(ty::FloatVar(v_id)), &ty::TyFloat(v)) => { - self.unify_float_variable(a_is_expected, v_id, v) - } - (&ty::TyFloat(v), &ty::TyInfer(ty::FloatVar(v_id))) => { - self.unify_float_variable(!a_is_expected, v_id, v) - } - - // All other cases of inference are errors - (&ty::TyInfer(_), _) | - (_, &ty::TyInfer(_)) => { - Err(TypeError::Sorts(ty::relate::expected_found(relation, &a, &b))) - } - - - _ => { - ty::relate::super_relate_tys(relation, a, b) - } + { + self.float_unification_table + .borrow_mut() + .unify_var_value(vid, val) + .map_err(|e| float_unification_error(vid_is_expected, e))?; + Ok(self.tcx.mk_mach_float(val)) } } -fn unify_integral_variable(&self, - vid_is_expected: bool, - vid: ty::IntVid, - val: ty::IntVarValue) - -> RelateResult<'tcx, Ty<'tcx>> -{ - self.int_unification_table - .borrow_mut() - .unify_var_value(vid, val) - .map_err(|e| int_unification_error(vid_is_expected, e))?; - match val { - IntType(v) => Ok(self.tcx.mk_mach_int(v)), - UintType(v) => Ok(self.tcx.mk_mach_uint(v)), - } -} - -fn unify_float_variable(&self, - vid_is_expected: bool, - vid: ty::FloatVid, - val: ast::FloatTy) - -> RelateResult<'tcx, Ty<'tcx>> -{ - self.float_unification_table - .borrow_mut() - .unify_var_value(vid, val) - .map_err(|e| float_unification_error(vid_is_expected, e))?; - Ok(self.tcx.mk_mach_float(val)) -} -} - impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { pub fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.infcx.tcx diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index 63d462b9f4f..6814d50107f 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -422,169 +422,169 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { region_vars } -pub fn skolemize_late_bound_regions(&self, - binder: &ty::Binder, - snapshot: &CombinedSnapshot) - -> (T, SkolemizationMap) - where T : TypeFoldable<'tcx> -{ - /*! - * Replace all regions bound by `binder` with skolemized regions and - * return a map indicating which bound-region was replaced with what - * skolemized region. This is the first step of checking subtyping - * when higher-ranked things are involved. See `README.md` for more - * details. - */ + pub fn skolemize_late_bound_regions(&self, + binder: &ty::Binder, + snapshot: &CombinedSnapshot) + -> (T, SkolemizationMap) + where T : TypeFoldable<'tcx> + { + /*! + * Replace all regions bound by `binder` with skolemized regions and + * return a map indicating which bound-region was replaced with what + * skolemized region. This is the first step of checking subtyping + * when higher-ranked things are involved. See `README.md` for more + * details. + */ - let (result, map) = self.tcx.replace_late_bound_regions(binder, |br| { - self.region_vars.new_skolemized(br, &snapshot.region_vars_snapshot) - }); + let (result, map) = self.tcx.replace_late_bound_regions(binder, |br| { + self.region_vars.new_skolemized(br, &snapshot.region_vars_snapshot) + }); - debug!("skolemize_bound_regions(binder={:?}, result={:?}, map={:?})", - binder, - result, - map); + debug!("skolemize_bound_regions(binder={:?}, result={:?}, map={:?})", + binder, + result, + map); - (result, map) -} - -pub fn leak_check(&self, - overly_polymorphic: bool, - skol_map: &SkolemizationMap, - snapshot: &CombinedSnapshot) - -> RelateResult<'tcx, ()> -{ - /*! - * Searches the region constriants created since `snapshot` was started - * and checks to determine whether any of the skolemized regions created - * in `skol_map` would "escape" -- meaning that they are related to - * other regions in some way. If so, the higher-ranked subtyping doesn't - * hold. See `README.md` for more details. - */ - - debug!("leak_check: skol_map={:?}", - skol_map); - - let new_vars = self.region_vars_confined_to_snapshot(snapshot); - for (&skol_br, &skol) in skol_map { - let tainted = self.tainted_regions(snapshot, skol); - for &tainted_region in &tainted { - // Each skolemized should only be relatable to itself - // or new variables: - match tainted_region { - ty::ReVar(vid) => { - if new_vars.iter().any(|&x| x == vid) { continue; } - } - _ => { - if tainted_region == skol { continue; } - } - }; - - debug!("{:?} (which replaced {:?}) is tainted by {:?}", - skol, - skol_br, - tainted_region); - - if overly_polymorphic { - debug!("Overly polymorphic!"); - return Err(TypeError::RegionsOverlyPolymorphic(skol_br, - tainted_region)); - } else { - debug!("Not as polymorphic!"); - return Err(TypeError::RegionsInsufficientlyPolymorphic(skol_br, - tainted_region)); - } - } + (result, map) } - Ok(()) -} -/// This code converts from skolemized regions back to late-bound -/// regions. It works by replacing each region in the taint set of a -/// skolemized region with a bound-region. The bound region will be bound -/// by the outer-most binder in `value`; the caller must ensure that there is -/// such a binder and it is the right place. -/// -/// This routine is only intended to be used when the leak-check has -/// passed; currently, it's used in the trait matching code to create -/// a set of nested obligations frmo an impl that matches against -/// something higher-ranked. More details can be found in -/// `librustc/middle/traits/README.md`. -/// -/// As a brief example, consider the obligation `for<'a> Fn(&'a int) -/// -> &'a int`, and the impl: -/// -/// impl Fn for SomethingOrOther -/// where A : Clone -/// { ... } -/// -/// Here we will have replaced `'a` with a skolemized region -/// `'0`. This means that our substitution will be `{A=>&'0 -/// int, R=>&'0 int}`. -/// -/// When we apply the substitution to the bounds, we will wind up with -/// `&'0 int : Clone` as a predicate. As a last step, we then go and -/// replace `'0` with a late-bound region `'a`. The depth is matched -/// to the depth of the predicate, in this case 1, so that the final -/// predicate is `for<'a> &'a int : Clone`. -pub fn plug_leaks(&self, - skol_map: SkolemizationMap, - snapshot: &CombinedSnapshot, - value: &T) -> T - where T : TypeFoldable<'tcx> -{ - debug_assert!(self.leak_check(false, &skol_map, snapshot).is_ok()); + pub fn leak_check(&self, + overly_polymorphic: bool, + skol_map: &SkolemizationMap, + snapshot: &CombinedSnapshot) + -> RelateResult<'tcx, ()> + { + /*! + * Searches the region constriants created since `snapshot` was started + * and checks to determine whether any of the skolemized regions created + * in `skol_map` would "escape" -- meaning that they are related to + * other regions in some way. If so, the higher-ranked subtyping doesn't + * hold. See `README.md` for more details. + */ - debug!("plug_leaks(skol_map={:?}, value={:?})", - skol_map, - value); + debug!("leak_check: skol_map={:?}", + skol_map); - // Compute a mapping from the "taint set" of each skolemized - // region back to the `ty::BoundRegion` that it originally - // represented. Because `leak_check` passed, we know that - // these taint sets are mutually disjoint. - let inv_skol_map: FnvHashMap = - skol_map - .into_iter() - .flat_map(|(skol_br, skol)| { - self.tainted_regions(snapshot, skol) - .into_iter() - .map(move |tainted_region| (tainted_region, skol_br)) - }) - .collect(); + let new_vars = self.region_vars_confined_to_snapshot(snapshot); + for (&skol_br, &skol) in skol_map { + let tainted = self.tainted_regions(snapshot, skol); + for &tainted_region in &tainted { + // Each skolemized should only be relatable to itself + // or new variables: + match tainted_region { + ty::ReVar(vid) => { + if new_vars.iter().any(|&x| x == vid) { continue; } + } + _ => { + if tainted_region == skol { continue; } + } + }; - debug!("plug_leaks: inv_skol_map={:?}", - inv_skol_map); + debug!("{:?} (which replaced {:?}) is tainted by {:?}", + skol, + skol_br, + tainted_region); - // Remove any instantiated type variables from `value`; those can hide - // references to regions from the `fold_regions` code below. - let value = self.resolve_type_vars_if_possible(value); - - // Map any skolemization byproducts back to a late-bound - // region. Put that late-bound region at whatever the outermost - // binder is that we encountered in `value`. The caller is - // responsible for ensuring that (a) `value` contains at least one - // binder and (b) that binder is the one we want to use. - let result = self.tcx.fold_regions(&value, &mut false, |r, current_depth| { - match inv_skol_map.get(&r) { - None => r, - Some(br) => { - // It is the responsibility of the caller to ensure - // that each skolemized region appears within a - // binder. In practice, this routine is only used by - // trait checking, and all of the skolemized regions - // appear inside predicates, which always have - // binders, so this assert is satisfied. - assert!(current_depth > 1); - - ty::ReLateBound(ty::DebruijnIndex::new(current_depth - 1), br.clone()) + if overly_polymorphic { + debug!("Overly polymorphic!"); + return Err(TypeError::RegionsOverlyPolymorphic(skol_br, + tainted_region)); + } else { + debug!("Not as polymorphic!"); + return Err(TypeError::RegionsInsufficientlyPolymorphic(skol_br, + tainted_region)); + } } } - }); + Ok(()) + } - debug!("plug_leaks: result={:?}", - result); + /// This code converts from skolemized regions back to late-bound + /// regions. It works by replacing each region in the taint set of a + /// skolemized region with a bound-region. The bound region will be bound + /// by the outer-most binder in `value`; the caller must ensure that there is + /// such a binder and it is the right place. + /// + /// This routine is only intended to be used when the leak-check has + /// passed; currently, it's used in the trait matching code to create + /// a set of nested obligations frmo an impl that matches against + /// something higher-ranked. More details can be found in + /// `librustc/middle/traits/README.md`. + /// + /// As a brief example, consider the obligation `for<'a> Fn(&'a int) + /// -> &'a int`, and the impl: + /// + /// impl Fn for SomethingOrOther + /// where A : Clone + /// { ... } + /// + /// Here we will have replaced `'a` with a skolemized region + /// `'0`. This means that our substitution will be `{A=>&'0 + /// int, R=>&'0 int}`. + /// + /// When we apply the substitution to the bounds, we will wind up with + /// `&'0 int : Clone` as a predicate. As a last step, we then go and + /// replace `'0` with a late-bound region `'a`. The depth is matched + /// to the depth of the predicate, in this case 1, so that the final + /// predicate is `for<'a> &'a int : Clone`. + pub fn plug_leaks(&self, + skol_map: SkolemizationMap, + snapshot: &CombinedSnapshot, + value: &T) -> T + where T : TypeFoldable<'tcx> + { + debug_assert!(self.leak_check(false, &skol_map, snapshot).is_ok()); - result -} + debug!("plug_leaks(skol_map={:?}, value={:?})", + skol_map, + value); + + // Compute a mapping from the "taint set" of each skolemized + // region back to the `ty::BoundRegion` that it originally + // represented. Because `leak_check` passed, we know that + // these taint sets are mutually disjoint. + let inv_skol_map: FnvHashMap = + skol_map + .into_iter() + .flat_map(|(skol_br, skol)| { + self.tainted_regions(snapshot, skol) + .into_iter() + .map(move |tainted_region| (tainted_region, skol_br)) + }) + .collect(); + + debug!("plug_leaks: inv_skol_map={:?}", + inv_skol_map); + + // Remove any instantiated type variables from `value`; those can hide + // references to regions from the `fold_regions` code below. + let value = self.resolve_type_vars_if_possible(value); + + // Map any skolemization byproducts back to a late-bound + // region. Put that late-bound region at whatever the outermost + // binder is that we encountered in `value`. The caller is + // responsible for ensuring that (a) `value` contains at least one + // binder and (b) that binder is the one we want to use. + let result = self.tcx.fold_regions(&value, &mut false, |r, current_depth| { + match inv_skol_map.get(&r) { + None => r, + Some(br) => { + // It is the responsibility of the caller to ensure + // that each skolemized region appears within a + // binder. In practice, this routine is only used by + // trait checking, and all of the skolemized regions + // appear inside predicates, which always have + // binders, so this assert is satisfied. + assert!(current_depth > 1); + + ty::ReLateBound(ty::DebruijnIndex::new(current_depth - 1), br.clone()) + } + } + }); + + debug!("plug_leaks: result={:?}", + result); + + result + } } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index fe9e128d8a6..29d8a808de5 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -628,53 +628,53 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result) } -pub fn drain_fulfillment_cx_or_panic(&self, - span: Span, - fulfill_cx: &mut traits::FulfillmentContext<'tcx>, - result: &T) - -> T::Lifted - where T: TypeFoldable<'tcx> + ty::Lift<'gcx> -{ - let when = "resolving bounds after type-checking"; - let v = match self.drain_fulfillment_cx(fulfill_cx, result) { - Ok(v) => v, - Err(errors) => { - span_bug!(span, "Encountered errors `{:?}` {}", errors, when); - } - }; + pub fn drain_fulfillment_cx_or_panic(&self, + span: Span, + fulfill_cx: &mut traits::FulfillmentContext<'tcx>, + result: &T) + -> T::Lifted + where T: TypeFoldable<'tcx> + ty::Lift<'gcx> + { + let when = "resolving bounds after type-checking"; + let v = match self.drain_fulfillment_cx(fulfill_cx, result) { + Ok(v) => v, + Err(errors) => { + span_bug!(span, "Encountered errors `{:?}` {}", errors, when); + } + }; - match self.tcx.lift_to_global(&v) { - Some(v) => v, - None => { - span_bug!(span, "Uninferred types/regions in `{:?}` {}", v, when); + match self.tcx.lift_to_global(&v) { + Some(v) => v, + None => { + span_bug!(span, "Uninferred types/regions in `{:?}` {}", v, when); + } } } -} -/// Finishes processes any obligations that remain in the fulfillment -/// context, and then "freshens" and returns `result`. This is -/// primarily used during normalization and other cases where -/// processing the obligations in `fulfill_cx` may cause type -/// inference variables that appear in `result` to be unified, and -/// hence we need to process those obligations to get the complete -/// picture of the type. -pub fn drain_fulfillment_cx(&self, - fulfill_cx: &mut traits::FulfillmentContext<'tcx>, - result: &T) - -> Result>> - where T : TypeFoldable<'tcx> -{ - debug!("drain_fulfillment_cx(result={:?})", - result); + /// Finishes processes any obligations that remain in the fulfillment + /// context, and then "freshens" and returns `result`. This is + /// primarily used during normalization and other cases where + /// processing the obligations in `fulfill_cx` may cause type + /// inference variables that appear in `result` to be unified, and + /// hence we need to process those obligations to get the complete + /// picture of the type. + pub fn drain_fulfillment_cx(&self, + fulfill_cx: &mut traits::FulfillmentContext<'tcx>, + result: &T) + -> Result>> + where T : TypeFoldable<'tcx> + { + debug!("drain_fulfillment_cx(result={:?})", + result); - // In principle, we only need to do this so long as `result` - // contains unbound type parameters. It could be a slight - // optimization to stop iterating early. - fulfill_cx.select_all_or_error(self)?; + // In principle, we only need to do this so long as `result` + // contains unbound type parameters. It could be a slight + // optimization to stop iterating early. + fulfill_cx.select_all_or_error(self)?; - let result = self.resolve_type_vars_if_possible(result); - Ok(self.tcx.erase_regions(&result)) -} + let result = self.resolve_type_vars_if_possible(result); + Ok(self.tcx.erase_regions(&result)) + } pub fn projection_mode(&self) -> ProjectionMode { self.projection_mode diff --git a/src/librustc/middle/astconv_util.rs b/src/librustc/middle/astconv_util.rs index 4129c53c988..8f97a89e654 100644 --- a/src/librustc/middle/astconv_util.rs +++ b/src/librustc/middle/astconv_util.rs @@ -21,63 +21,63 @@ use syntax::codemap::Span; use hir as ast; impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { -pub fn prohibit_type_params(self, segments: &[ast::PathSegment]) { - for segment in segments { - for typ in segment.parameters.types() { - span_err!(self.sess, typ.span, E0109, - "type parameters are not allowed on this type"); - break; - } - for lifetime in segment.parameters.lifetimes() { - span_err!(self.sess, lifetime.span, E0110, - "lifetime parameters are not allowed on this type"); - break; - } - for binding in segment.parameters.bindings() { - self.prohibit_projection(binding.span); - break; - } - } -} - -pub fn prohibit_projection(self, span: Span) -{ - span_err!(self.sess, span, E0229, - "associated type bindings are not allowed here"); -} - -pub fn prim_ty_to_ty(self, - segments: &[ast::PathSegment], - nty: ast::PrimTy) - -> Ty<'tcx> { - self.prohibit_type_params(segments); - match nty { - ast::TyBool => self.types.bool, - ast::TyChar => self.types.char, - ast::TyInt(it) => self.mk_mach_int(it), - ast::TyUint(uit) => self.mk_mach_uint(uit), - ast::TyFloat(ft) => self.mk_mach_float(ft), - ast::TyStr => self.mk_str() - } -} - -/// If a type in the AST is a primitive type, return the ty::Ty corresponding -/// to it. -pub fn ast_ty_to_prim_ty(self, ast_ty: &ast::Ty) -> Option> { - if let ast::TyPath(None, ref path) = ast_ty.node { - let def = match self.def_map.borrow().get(&ast_ty.id) { - None => { - span_bug!(ast_ty.span, "unbound path {:?}", path) + pub fn prohibit_type_params(self, segments: &[ast::PathSegment]) { + for segment in segments { + for typ in segment.parameters.types() { + span_err!(self.sess, typ.span, E0109, + "type parameters are not allowed on this type"); + break; + } + for lifetime in segment.parameters.lifetimes() { + span_err!(self.sess, lifetime.span, E0110, + "lifetime parameters are not allowed on this type"); + break; + } + for binding in segment.parameters.bindings() { + self.prohibit_projection(binding.span); + break; + } + } + } + + pub fn prohibit_projection(self, span: Span) + { + span_err!(self.sess, span, E0229, + "associated type bindings are not allowed here"); + } + + pub fn prim_ty_to_ty(self, + segments: &[ast::PathSegment], + nty: ast::PrimTy) + -> Ty<'tcx> { + self.prohibit_type_params(segments); + match nty { + ast::TyBool => self.types.bool, + ast::TyChar => self.types.char, + ast::TyInt(it) => self.mk_mach_int(it), + ast::TyUint(uit) => self.mk_mach_uint(uit), + ast::TyFloat(ft) => self.mk_mach_float(ft), + ast::TyStr => self.mk_str() + } + } + + /// If a type in the AST is a primitive type, return the ty::Ty corresponding + /// to it. + pub fn ast_ty_to_prim_ty(self, ast_ty: &ast::Ty) -> Option> { + if let ast::TyPath(None, ref path) = ast_ty.node { + let def = match self.def_map.borrow().get(&ast_ty.id) { + None => { + span_bug!(ast_ty.span, "unbound path {:?}", path) + } + Some(d) => d.full_def() + }; + if let Def::PrimTy(nty) = def { + Some(self.prim_ty_to_ty(&path.segments, nty)) + } else { + None } - Some(d) => d.full_def() - }; - if let Def::PrimTy(nty) = def { - Some(self.prim_ty_to_ty(&path.segments, nty)) } else { None } - } else { - None } } -} diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 9fabdf58b6f..c2db6de0370 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -670,46 +670,46 @@ fn is_staged_api<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> bool { } impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { -/// Lookup the stability for a node, loading external crate -/// metadata as necessary. -pub fn lookup_stability(self, id: DefId) -> Option<&'tcx Stability> { - if let Some(st) = self.stability.borrow().stab_map.get(&id) { - return *st; + /// Lookup the stability for a node, loading external crate + /// metadata as necessary. + pub fn lookup_stability(self, id: DefId) -> Option<&'tcx Stability> { + if let Some(st) = self.stability.borrow().stab_map.get(&id) { + return *st; + } + + let st = self.lookup_stability_uncached(id); + self.stability.borrow_mut().stab_map.insert(id, st); + st } - let st = self.lookup_stability_uncached(id); - self.stability.borrow_mut().stab_map.insert(id, st); - st -} + pub fn lookup_deprecation(self, id: DefId) -> Option { + if let Some(depr) = self.stability.borrow().depr_map.get(&id) { + return depr.clone(); + } -pub fn lookup_deprecation(self, id: DefId) -> Option { - if let Some(depr) = self.stability.borrow().depr_map.get(&id) { - return depr.clone(); + let depr = self.lookup_deprecation_uncached(id); + self.stability.borrow_mut().depr_map.insert(id, depr.clone()); + depr } - let depr = self.lookup_deprecation_uncached(id); - self.stability.borrow_mut().depr_map.insert(id, depr.clone()); - depr -} - -fn lookup_stability_uncached(self, id: DefId) -> Option<&'tcx Stability> { - debug!("lookup(id={:?})", id); - if id.is_local() { - None // The stability cache is filled partially lazily - } else { - self.sess.cstore.stability(id).map(|st| self.intern_stability(st)) + fn lookup_stability_uncached(self, id: DefId) -> Option<&'tcx Stability> { + debug!("lookup(id={:?})", id); + if id.is_local() { + None // The stability cache is filled partially lazily + } else { + self.sess.cstore.stability(id).map(|st| self.intern_stability(st)) + } } -} -fn lookup_deprecation_uncached(self, id: DefId) -> Option { - debug!("lookup(id={:?})", id); - if id.is_local() { - None // The stability cache is filled partially lazily - } else { - self.sess.cstore.deprecation(id) + fn lookup_deprecation_uncached(self, id: DefId) -> Option { + debug!("lookup(id={:?})", id); + if id.is_local() { + None // The stability cache is filled partially lazily + } else { + self.sess.cstore.deprecation(id) + } } } -} /// Given the list of enabled features that were not language features (i.e. that /// were expected to be library features), and the list of features used from diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index bc573d956a7..6c037ebd2bc 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -61,840 +61,844 @@ impl<'a, 'gcx, 'tcx> TraitErrorKey<'tcx> { } impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { -pub fn report_fulfillment_errors(&self, errors: &Vec>) { - for error in errors { - self.report_fulfillment_error(error, None); - } -} - -pub fn report_fulfillment_errors_as_warnings(&self, - errors: &Vec>, - node_id: ast::NodeId) { - for error in errors { - self.report_fulfillment_error(error, Some(node_id)); - } -} - -fn report_fulfillment_error(&self, - error: &FulfillmentError<'tcx>, - warning_node_id: Option) { - let error_key = TraitErrorKey::from_error(self, error, warning_node_id); - debug!("report_fulfillment_errors({:?}) - key={:?}", - error, error_key); - if !self.reported_trait_errors.borrow_mut().insert(error_key) { - debug!("report_fulfillment_errors: skipping duplicate"); - return; - } - match error.code { - FulfillmentErrorCode::CodeSelectionError(ref e) => { - self.report_selection_error(&error.obligation, e, warning_node_id); - } - FulfillmentErrorCode::CodeProjectionError(ref e) => { - self.report_projection_error(&error.obligation, e, warning_node_id); - } - FulfillmentErrorCode::CodeAmbiguity => { - self.maybe_report_ambiguity(&error.obligation); + pub fn report_fulfillment_errors(&self, errors: &Vec>) { + for error in errors { + self.report_fulfillment_error(error, None); } } -} -fn report_projection_error(&self, - obligation: &PredicateObligation<'tcx>, - error: &MismatchedProjectionTypes<'tcx>, - warning_node_id: Option) -{ - let predicate = - self.resolve_type_vars_if_possible(&obligation.predicate); - - if !predicate.references_error() { - if let Some(warning_node_id) = warning_node_id { - self.tcx.sess.add_lint( - ::lint::builtin::UNSIZED_IN_TUPLE, - warning_node_id, - obligation.cause.span, - format!("type mismatch resolving `{}`: {}", - predicate, - error.err)); - } else { - let mut err = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, - "type mismatch resolving `{}`: {}", - predicate, - error.err); - self.note_obligation_cause(&mut err, obligation); - err.emit(); + pub fn report_fulfillment_errors_as_warnings(&self, + errors: &Vec>, + node_id: ast::NodeId) { + for error in errors { + self.report_fulfillment_error(error, Some(node_id)); } } -} -fn on_unimplemented_note(&self, - trait_ref: ty::PolyTraitRef<'tcx>, - span: Span) -> Option { - let trait_ref = trait_ref.skip_binder(); - let def_id = trait_ref.def_id; - let mut report = None; - for item in self.tcx.get_attrs(def_id).iter() { - if item.check_name("rustc_on_unimplemented") { - let err_sp = item.meta().span.substitute_dummy(span); - let def = self.tcx.lookup_trait_def(def_id); - let trait_str = def.trait_ref.to_string(); - if let Some(ref istring) = item.value_str() { - let mut generic_map = def.generics.types.iter_enumerated() - .map(|(param, i, gen)| { - (gen.name.as_str().to_string(), - trait_ref.substs.types.get(param, i) - .to_string()) - }).collect::>(); - generic_map.insert("Self".to_string(), - trait_ref.self_ty().to_string()); - let parser = Parser::new(&istring); - let mut errored = false; - let err: String = parser.filter_map(|p| { - match p { - Piece::String(s) => Some(s), - Piece::NextArgument(a) => match a.position { - Position::ArgumentNamed(s) => match generic_map.get(s) { - Some(val) => Some(val), - None => { - span_err!(self.tcx.sess, err_sp, E0272, - "the #[rustc_on_unimplemented] \ - attribute on \ - trait definition for {} refers to \ - non-existent type parameter {}", - trait_str, s); - errored = true; - None - } - }, - _ => { - span_err!(self.tcx.sess, err_sp, E0273, - "the #[rustc_on_unimplemented] \ - attribute on \ - trait definition for {} must have named \ - format arguments, \ - eg `#[rustc_on_unimplemented = \ - \"foo {{T}}\"]`", - trait_str); - errored = true; - None - } - } - } - }).collect(); - // Report only if the format string checks out - if !errored { - report = Some(err); - } + fn report_fulfillment_error(&self, + error: &FulfillmentError<'tcx>, + warning_node_id: Option) { + let error_key = TraitErrorKey::from_error(self, error, warning_node_id); + debug!("report_fulfillment_errors({:?}) - key={:?}", + error, error_key); + if !self.reported_trait_errors.borrow_mut().insert(error_key) { + debug!("report_fulfillment_errors: skipping duplicate"); + return; + } + match error.code { + FulfillmentErrorCode::CodeSelectionError(ref e) => { + self.report_selection_error(&error.obligation, e, warning_node_id); + } + FulfillmentErrorCode::CodeProjectionError(ref e) => { + self.report_projection_error(&error.obligation, e, warning_node_id); + } + FulfillmentErrorCode::CodeAmbiguity => { + self.maybe_report_ambiguity(&error.obligation); + } + } + } + + fn report_projection_error(&self, + obligation: &PredicateObligation<'tcx>, + error: &MismatchedProjectionTypes<'tcx>, + warning_node_id: Option) + { + let predicate = + self.resolve_type_vars_if_possible(&obligation.predicate); + + if !predicate.references_error() { + if let Some(warning_node_id) = warning_node_id { + self.tcx.sess.add_lint( + ::lint::builtin::UNSIZED_IN_TUPLE, + warning_node_id, + obligation.cause.span, + format!("type mismatch resolving `{}`: {}", + predicate, + error.err)); } else { - span_err!(self.tcx.sess, err_sp, E0274, - "the #[rustc_on_unimplemented] attribute on \ - trait definition for {} must have a value, \ - eg `#[rustc_on_unimplemented = \"foo\"]`", - trait_str); - } - break; - } - } - report -} - -fn report_similar_impl_candidates(&self, - trait_ref: ty::PolyTraitRef<'tcx>, - err: &mut DiagnosticBuilder) -{ - let simp = fast_reject::simplify_type(self.tcx, - trait_ref.skip_binder().self_ty(), - true); - let mut impl_candidates = Vec::new(); - let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id()); - - match simp { - Some(simp) => trait_def.for_each_impl(self.tcx, |def_id| { - let imp = self.tcx.impl_trait_ref(def_id).unwrap(); - let imp_simp = fast_reject::simplify_type(self.tcx, - imp.self_ty(), - true); - if let Some(imp_simp) = imp_simp { - if simp != imp_simp { - return; - } - } - impl_candidates.push(imp); - }), - None => trait_def.for_each_impl(self.tcx, |def_id| { - impl_candidates.push( - self.tcx.impl_trait_ref(def_id).unwrap()); - }) - }; - - if impl_candidates.is_empty() { - return; - } - - err.help(&format!("the following implementations were found:")); - - let end = cmp::min(4, impl_candidates.len()); - for candidate in &impl_candidates[0..end] { - err.help(&format!(" {:?}", candidate)); - } - if impl_candidates.len() > 4 { - err.help(&format!("and {} others", impl_candidates.len()-4)); - } -} - -/// Reports that an overflow has occurred and halts compilation. We -/// halt compilation unconditionally because it is important that -/// overflows never be masked -- they basically represent computations -/// whose result could not be truly determined and thus we can't say -/// if the program type checks or not -- and they are unusual -/// occurrences in any case. -pub fn report_overflow_error(&self, - obligation: &Obligation<'tcx, T>, - suggest_increasing_limit: bool) -> ! - where T: fmt::Display + TypeFoldable<'tcx> -{ - let predicate = - self.resolve_type_vars_if_possible(&obligation.predicate); - let mut err = struct_span_err!(self.tcx.sess, obligation.cause.span, E0275, - "overflow evaluating the requirement `{}`", - predicate); - - if suggest_increasing_limit { - self.suggest_new_overflow_limit(&mut err); - } - - self.note_obligation_cause(&mut err, obligation); - - err.emit(); - self.tcx.sess.abort_if_errors(); - bug!(); -} - -/// Reports that a cycle was detected which led to overflow and halts -/// compilation. This is equivalent to `report_overflow_error` except -/// that we can give a more helpful error message (and, in particular, -/// we do not suggest increasing the overflow limit, which is not -/// going to help). -pub fn report_overflow_error_cycle(&self, cycle: &Vec>) -> ! { - assert!(cycle.len() > 1); - - debug!("report_overflow_error_cycle(cycle length = {})", cycle.len()); - - let cycle = self.resolve_type_vars_if_possible(cycle); - - debug!("report_overflow_error_cycle: cycle={:?}", cycle); - - assert_eq!(&cycle[0].predicate, &cycle.last().unwrap().predicate); - - self.try_report_overflow_error_type_of_infinite_size(&cycle); - self.report_overflow_error(&cycle[0], false); -} - -/// If a cycle results from evaluated whether something is Sized, that -/// is a particular special case that always results from a struct or -/// enum definition that lacks indirection (e.g., `struct Foo { x: Foo -/// }`). We wish to report a targeted error for this case. -pub fn try_report_overflow_error_type_of_infinite_size(&self, - cycle: &[PredicateObligation<'tcx>]) -{ - let sized_trait = match self.tcx.lang_items.sized_trait() { - Some(v) => v, - None => return, - }; - let top_is_sized = { - match cycle[0].predicate { - ty::Predicate::Trait(ref data) => data.def_id() == sized_trait, - _ => false, - } - }; - if !top_is_sized { - return; - } - - // The only way to have a type of infinite size is to have, - // somewhere, a struct/enum type involved. Identify all such types - // and report the cycle to the user. - - let struct_enum_tys: Vec<_> = - cycle.iter() - .flat_map(|obligation| match obligation.predicate { - ty::Predicate::Trait(ref data) => { - assert_eq!(data.def_id(), sized_trait); - let self_ty = data.skip_binder().trait_ref.self_ty(); // (*) - // (*) ok to skip binder because this is just - // error reporting and regions don't really - // matter - match self_ty.sty { - ty::TyEnum(..) | ty::TyStruct(..) => Some(self_ty), - _ => None, - } - } - _ => { - span_bug!(obligation.cause.span, - "Sized cycle involving non-trait-ref: {:?}", - obligation.predicate); - } - }) - .collect(); - - assert!(!struct_enum_tys.is_empty()); - - // This is a bit tricky. We want to pick a "main type" in the - // listing that is local to the current crate, so we can give a - // good span to the user. But it might not be the first one in our - // cycle list. So find the first one that is local and then - // rotate. - let (main_index, main_def_id) = - struct_enum_tys.iter() - .enumerate() - .filter_map(|(index, ty)| match ty.sty { - ty::TyEnum(adt_def, _) | ty::TyStruct(adt_def, _) - if adt_def.did.is_local() => - Some((index, adt_def.did)), - _ => - None, - }) - .next() - .unwrap(); // should always be SOME local type involved! - - // Rotate so that the "main" type is at index 0. - let struct_enum_tys: Vec<_> = - struct_enum_tys.iter() - .cloned() - .skip(main_index) - .chain(struct_enum_tys.iter().cloned().take(main_index)) - .collect(); - - let tcx = self.tcx; - let mut err = tcx.recursive_type_with_infinite_size_error(main_def_id); - let len = struct_enum_tys.len(); - if len > 2 { - err.note(&format!("type `{}` is embedded within `{}`...", - struct_enum_tys[0], - struct_enum_tys[1])); - for &next_ty in &struct_enum_tys[1..len-1] { - err.note(&format!("...which in turn is embedded within `{}`...", next_ty)); - } - err.note(&format!("...which in turn is embedded within `{}`, \ - completing the cycle.", - struct_enum_tys[len-1])); - } - err.emit(); - self.tcx.sess.abort_if_errors(); - bug!(); -} - -pub fn report_selection_error(&self, - obligation: &PredicateObligation<'tcx>, - error: &SelectionError<'tcx>, - warning_node_id: Option) -{ - let span = obligation.cause.span; - let mut err = match *error { - SelectionError::Unimplemented => { - if let ObligationCauseCode::CompareImplMethodObligation = obligation.cause.code { - span_err!( - self.tcx.sess, span, E0276, - "the requirement `{}` appears on the impl \ - method but not on the corresponding trait method", - obligation.predicate); - return; - } else { - match obligation.predicate { - ty::Predicate::Trait(ref trait_predicate) => { - let trait_predicate = - self.resolve_type_vars_if_possible(trait_predicate); - - if self.tcx.sess.has_errors() && trait_predicate.references_error() { - return; - } else { - let trait_ref = trait_predicate.to_poly_trait_ref(); - - if let Some(warning_node_id) = warning_node_id { - self.tcx.sess.add_lint( - ::lint::builtin::UNSIZED_IN_TUPLE, - warning_node_id, - obligation.cause.span, - format!("the trait bound `{}` is not satisfied", - trait_ref.to_predicate())); - return; - } - - let mut err = struct_span_err!( - self.tcx.sess, span, E0277, - "the trait bound `{}` is not satisfied", - trait_ref.to_predicate()); - - // Try to report a help message - - if !trait_ref.has_infer_types() && - self.predicate_can_apply(trait_ref) - { - // If a where-clause may be useful, remind the - // user that they can add it. - // - // don't display an on-unimplemented note, as - // these notes will often be of the form - // "the type `T` can't be frobnicated" - // which is somewhat confusing. - err.help(&format!("consider adding a `where {}` bound", - trait_ref.to_predicate() - )); - } else if let Some(s) = self.on_unimplemented_note(trait_ref, span) { - // Otherwise, if there is an on-unimplemented note, - // display it. - err.note(&s); - } else { - // If we can't show anything useful, try to find - // similar impls. - - self.report_similar_impl_candidates(trait_ref, &mut err); - } - err - } - }, - ty::Predicate::Equate(ref predicate) => { - let predicate = self.resolve_type_vars_if_possible(predicate); - let err = self.equality_predicate(span, - &predicate).err().unwrap(); - struct_span_err!(self.tcx.sess, span, E0278, - "the requirement `{}` is not satisfied (`{}`)", - predicate, err) - } - - ty::Predicate::RegionOutlives(ref predicate) => { - let predicate = self.resolve_type_vars_if_possible(predicate); - let err = self.region_outlives_predicate(span, - &predicate).err().unwrap(); - struct_span_err!(self.tcx.sess, span, E0279, - "the requirement `{}` is not satisfied (`{}`)", - predicate, err) - } - - ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => { - let predicate = - self.resolve_type_vars_if_possible(&obligation.predicate); - struct_span_err!(self.tcx.sess, span, E0280, - "the requirement `{}` is not satisfied", - predicate) - } - - ty::Predicate::ObjectSafe(trait_def_id) => { - let violations = self.tcx.object_safety_violations(trait_def_id); - let err = self.tcx.report_object_safety_error(span, - trait_def_id, - warning_node_id, - violations); - if let Some(err) = err { - err - } else { - return; - } - } - - ty::Predicate::ClosureKind(closure_def_id, kind) => { - let found_kind = self.closure_kind(closure_def_id).unwrap(); - let closure_span = self.tcx.map.span_if_local(closure_def_id).unwrap(); - let mut err = struct_span_err!( - self.tcx.sess, closure_span, E0525, - "expected a closure that implements the `{}` trait, but this closure \ - only implements `{}`", - kind, - found_kind); - err.span_note( - obligation.cause.span, - &format!("the requirement to implement `{}` derives from here", kind)); - err.emit(); - return; - } - - ty::Predicate::WellFormed(ty) => { - // WF predicates cannot themselves make - // errors. They can only block due to - // ambiguity; otherwise, they always - // degenerate into other obligations - // (which may fail). - span_bug!(span, "WF predicate not satisfied for {:?}", ty); - } - - ty::Predicate::Rfc1592(ref data) => { - span_bug!( - obligation.cause.span, - "RFC1592 predicate not satisfied for {:?}", - data); - } - } - } - } - - OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, ref e) => { - let expected_trait_ref = self.resolve_type_vars_if_possible(&*expected_trait_ref); - let actual_trait_ref = self.resolve_type_vars_if_possible(&*actual_trait_ref); - if actual_trait_ref.self_ty().references_error() { - return; - } - struct_span_err!(self.tcx.sess, span, E0281, - "type mismatch: the type `{}` implements the trait `{}`, \ - but the trait `{}` is required ({})", - expected_trait_ref.self_ty(), - expected_trait_ref, - actual_trait_ref, - e) - } - - TraitNotObjectSafe(did) => { - let violations = self.tcx.object_safety_violations(did); - let err = self.tcx.report_object_safety_error(span, did, - warning_node_id, - violations); - if let Some(err) = err { - err - } else { - return; - } - } - }; - self.note_obligation_cause(&mut err, obligation); - err.emit(); -} -} - -impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { -pub fn recursive_type_with_infinite_size_error(self, - type_def_id: DefId) - -> DiagnosticBuilder<'tcx> -{ - assert!(type_def_id.is_local()); - let span = self.map.span_if_local(type_def_id).unwrap(); - let mut err = struct_span_err!(self.sess, span, E0072, "recursive type `{}` has infinite size", - self.item_path_str(type_def_id)); - err.help(&format!("insert indirection (e.g., a `Box`, `Rc`, or `&`) \ - at some point to make `{}` representable", - self.item_path_str(type_def_id))); - err -} - -pub fn report_object_safety_error(self, - span: Span, - trait_def_id: DefId, - warning_node_id: Option, - violations: Vec) - -> Option> -{ - let mut err = match warning_node_id { - Some(_) => None, - None => { - Some(struct_span_err!( - self.sess, span, E0038, - "the trait `{}` cannot be made into an object", - self.item_path_str(trait_def_id))) - } - }; - - let mut reported_violations = FnvHashSet(); - for violation in violations { - if !reported_violations.insert(violation.clone()) { - continue; - } - let buf; - let note = match violation { - ObjectSafetyViolation::SizedSelf => { - "the trait cannot require that `Self : Sized`" - } - - ObjectSafetyViolation::SupertraitSelf => { - "the trait cannot use `Self` as a type parameter \ - in the supertrait listing" - } - - ObjectSafetyViolation::Method(method, - MethodViolationCode::StaticMethod) => { - buf = format!("method `{}` has no receiver", - method.name); - &buf - } - - ObjectSafetyViolation::Method(method, - MethodViolationCode::ReferencesSelf) => { - buf = format!("method `{}` references the `Self` type \ - in its arguments or return type", - method.name); - &buf - } - - ObjectSafetyViolation::Method(method, - MethodViolationCode::Generic) => { - buf = format!("method `{}` has generic type parameters", - method.name); - &buf - } - }; - match (warning_node_id, &mut err) { - (Some(node_id), &mut None) => { - self.sess.add_lint( - ::lint::builtin::OBJECT_UNSAFE_FRAGMENT, - node_id, - span, - note.to_string()); - } - (None, &mut Some(ref mut err)) => { - err.note(note); - } - _ => unreachable!() - } - } - err -} -} - -impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { -fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) { - // Unable to successfully determine, probably means - // insufficient type information, but could mean - // ambiguous impls. The latter *ought* to be a - // coherence violation, so we don't report it here. - - let predicate = self.resolve_type_vars_if_possible(&obligation.predicate); - - debug!("maybe_report_ambiguity(predicate={:?}, obligation={:?})", - predicate, - obligation); - - // Ambiguity errors are often caused as fallout from earlier - // errors. So just ignore them if this infcx is tainted. - if self.is_tainted_by_errors() { - return; - } - - match predicate { - ty::Predicate::Trait(ref data) => { - let trait_ref = data.to_poly_trait_ref(); - let self_ty = trait_ref.self_ty(); - let all_types = &trait_ref.substs().types; - if all_types.references_error() { - } else { - // Typically, this ambiguity should only happen if - // there are unresolved type inference variables - // (otherwise it would suggest a coherence - // failure). But given #21974 that is not necessarily - // the case -- we can have multiple where clauses that - // are only distinguished by a region, which results - // in an ambiguity even when all types are fully - // known, since we don't dispatch based on region - // relationships. - - // This is kind of a hack: it frequently happens that some earlier - // error prevents types from being fully inferred, and then we get - // a bunch of uninteresting errors saying something like " doesn't implement Sized". It may even be true that we - // could just skip over all checks where the self-ty is an - // inference variable, but I was afraid that there might be an - // inference variable created, registered as an obligation, and - // then never forced by writeback, and hence by skipping here we'd - // be ignoring the fact that we don't KNOW the type works - // out. Though even that would probably be harmless, given that - // we're only talking about builtin traits, which are known to be - // inhabited. But in any case I just threw in this check for - // has_errors() to be sure that compilation isn't happening - // anyway. In that case, why inundate the user. - if !self.tcx.sess.has_errors() { - if - self.tcx.lang_items.sized_trait() - .map_or(false, |sized_id| sized_id == trait_ref.def_id()) - { - self.need_type_info(obligation.cause.span, self_ty); - } else { - let mut err = struct_span_err!(self.tcx.sess, obligation.cause.span, E0283, - "type annotations required: \ - cannot resolve `{}`", - predicate); - self.note_obligation_cause(&mut err, obligation); - err.emit(); - } - } - } - } - - ty::Predicate::WellFormed(ty) => { - // Same hacky approach as above to avoid deluging user - // with error messages. - if !ty.references_error() && !self.tcx.sess.has_errors() { - self.need_type_info(obligation.cause.span, ty); - } - } - - _ => { - if !self.tcx.sess.has_errors() { - let mut err = struct_span_err!(self.tcx.sess, obligation.cause.span, E0284, - "type annotations required: cannot resolve `{}`", - predicate); + let mut err = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, + "type mismatch resolving `{}`: {}", + predicate, + error.err); self.note_obligation_cause(&mut err, obligation); err.emit(); } } } -} -/// Returns whether the trait predicate may apply for *some* assignment -/// to the type parameters. -fn predicate_can_apply(&self, pred: ty::PolyTraitRef<'tcx>) -> bool { - struct ParamToVarFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, - var_map: FnvHashMap, Ty<'tcx>> + fn on_unimplemented_note(&self, + trait_ref: ty::PolyTraitRef<'tcx>, + span: Span) -> Option { + let trait_ref = trait_ref.skip_binder(); + let def_id = trait_ref.def_id; + let mut report = None; + for item in self.tcx.get_attrs(def_id).iter() { + if item.check_name("rustc_on_unimplemented") { + let err_sp = item.meta().span.substitute_dummy(span); + let def = self.tcx.lookup_trait_def(def_id); + let trait_str = def.trait_ref.to_string(); + if let Some(ref istring) = item.value_str() { + let mut generic_map = def.generics.types.iter_enumerated() + .map(|(param, i, gen)| { + (gen.name.as_str().to_string(), + trait_ref.substs.types.get(param, i) + .to_string()) + }).collect::>(); + generic_map.insert("Self".to_string(), + trait_ref.self_ty().to_string()); + let parser = Parser::new(&istring); + let mut errored = false; + let err: String = parser.filter_map(|p| { + match p { + Piece::String(s) => Some(s), + Piece::NextArgument(a) => match a.position { + Position::ArgumentNamed(s) => match generic_map.get(s) { + Some(val) => Some(val), + None => { + span_err!(self.tcx.sess, err_sp, E0272, + "the #[rustc_on_unimplemented] \ + attribute on \ + trait definition for {} refers to \ + non-existent type parameter {}", + trait_str, s); + errored = true; + None + } + }, + _ => { + span_err!(self.tcx.sess, err_sp, E0273, + "the #[rustc_on_unimplemented] attribute \ + on trait definition for {} must have \ + named format arguments, eg \ + `#[rustc_on_unimplemented = \ + \"foo {{T}}\"]`", trait_str); + errored = true; + None + } + } + } + }).collect(); + // Report only if the format string checks out + if !errored { + report = Some(err); + } + } else { + span_err!(self.tcx.sess, err_sp, E0274, + "the #[rustc_on_unimplemented] attribute on \ + trait definition for {} must have a value, \ + eg `#[rustc_on_unimplemented = \"foo\"]`", + trait_str); + } + break; + } + } + report } - impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for ParamToVarFolder<'a, 'gcx, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.infcx.tcx } + fn report_similar_impl_candidates(&self, + trait_ref: ty::PolyTraitRef<'tcx>, + err: &mut DiagnosticBuilder) + { + let simp = fast_reject::simplify_type(self.tcx, + trait_ref.skip_binder().self_ty(), + true); + let mut impl_candidates = Vec::new(); + let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id()); - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if let ty::TyParam(..) = ty.sty { - let infcx = self.infcx; - self.var_map.entry(ty).or_insert_with(|| infcx.next_ty_var()) - } else { - ty.super_fold_with(self) + match simp { + Some(simp) => trait_def.for_each_impl(self.tcx, |def_id| { + let imp = self.tcx.impl_trait_ref(def_id).unwrap(); + let imp_simp = fast_reject::simplify_type(self.tcx, + imp.self_ty(), + true); + if let Some(imp_simp) = imp_simp { + if simp != imp_simp { + return; + } + } + impl_candidates.push(imp); + }), + None => trait_def.for_each_impl(self.tcx, |def_id| { + impl_candidates.push( + self.tcx.impl_trait_ref(def_id).unwrap()); + }) + }; + + if impl_candidates.is_empty() { + return; + } + + err.help(&format!("the following implementations were found:")); + + let end = cmp::min(4, impl_candidates.len()); + for candidate in &impl_candidates[0..end] { + err.help(&format!(" {:?}", candidate)); + } + if impl_candidates.len() > 4 { + err.help(&format!("and {} others", impl_candidates.len()-4)); + } + } + + /// Reports that an overflow has occurred and halts compilation. We + /// halt compilation unconditionally because it is important that + /// overflows never be masked -- they basically represent computations + /// whose result could not be truly determined and thus we can't say + /// if the program type checks or not -- and they are unusual + /// occurrences in any case. + pub fn report_overflow_error(&self, + obligation: &Obligation<'tcx, T>, + suggest_increasing_limit: bool) -> ! + where T: fmt::Display + TypeFoldable<'tcx> + { + let predicate = + self.resolve_type_vars_if_possible(&obligation.predicate); + let mut err = struct_span_err!(self.tcx.sess, obligation.cause.span, E0275, + "overflow evaluating the requirement `{}`", + predicate); + + if suggest_increasing_limit { + self.suggest_new_overflow_limit(&mut err); + } + + self.note_obligation_cause(&mut err, obligation); + + err.emit(); + self.tcx.sess.abort_if_errors(); + bug!(); + } + + /// Reports that a cycle was detected which led to overflow and halts + /// compilation. This is equivalent to `report_overflow_error` except + /// that we can give a more helpful error message (and, in particular, + /// we do not suggest increasing the overflow limit, which is not + /// going to help). + pub fn report_overflow_error_cycle(&self, cycle: &Vec>) -> ! { + assert!(cycle.len() > 1); + + debug!("report_overflow_error_cycle(cycle length = {})", cycle.len()); + + let cycle = self.resolve_type_vars_if_possible(cycle); + + debug!("report_overflow_error_cycle: cycle={:?}", cycle); + + assert_eq!(&cycle[0].predicate, &cycle.last().unwrap().predicate); + + self.try_report_overflow_error_type_of_infinite_size(&cycle); + self.report_overflow_error(&cycle[0], false); + } + + /// If a cycle results from evaluated whether something is Sized, that + /// is a particular special case that always results from a struct or + /// enum definition that lacks indirection (e.g., `struct Foo { x: Foo + /// }`). We wish to report a targeted error for this case. + pub fn try_report_overflow_error_type_of_infinite_size(&self, + cycle: &[PredicateObligation<'tcx>]) + { + let sized_trait = match self.tcx.lang_items.sized_trait() { + Some(v) => v, + None => return, + }; + let top_is_sized = { + match cycle[0].predicate { + ty::Predicate::Trait(ref data) => data.def_id() == sized_trait, + _ => false, + } + }; + if !top_is_sized { + return; + } + + // The only way to have a type of infinite size is to have, + // somewhere, a struct/enum type involved. Identify all such types + // and report the cycle to the user. + + let struct_enum_tys: Vec<_> = + cycle.iter() + .flat_map(|obligation| match obligation.predicate { + ty::Predicate::Trait(ref data) => { + assert_eq!(data.def_id(), sized_trait); + let self_ty = data.skip_binder().trait_ref.self_ty(); // (*) + // (*) ok to skip binder because this is just + // error reporting and regions don't really + // matter + match self_ty.sty { + ty::TyEnum(..) | ty::TyStruct(..) => Some(self_ty), + _ => None, + } + } + _ => { + span_bug!(obligation.cause.span, + "Sized cycle involving non-trait-ref: {:?}", + obligation.predicate); + } + }) + .collect(); + + assert!(!struct_enum_tys.is_empty()); + + // This is a bit tricky. We want to pick a "main type" in the + // listing that is local to the current crate, so we can give a + // good span to the user. But it might not be the first one in our + // cycle list. So find the first one that is local and then + // rotate. + let (main_index, main_def_id) = + struct_enum_tys.iter() + .enumerate() + .filter_map(|(index, ty)| match ty.sty { + ty::TyEnum(adt_def, _) | ty::TyStruct(adt_def, _) + if adt_def.did.is_local() => + Some((index, adt_def.did)), + _ => + None, + }) + .next() + .unwrap(); // should always be SOME local type involved! + + // Rotate so that the "main" type is at index 0. + let struct_enum_tys: Vec<_> = + struct_enum_tys.iter() + .cloned() + .skip(main_index) + .chain(struct_enum_tys.iter().cloned().take(main_index)) + .collect(); + + let tcx = self.tcx; + let mut err = tcx.recursive_type_with_infinite_size_error(main_def_id); + let len = struct_enum_tys.len(); + if len > 2 { + err.note(&format!("type `{}` is embedded within `{}`...", + struct_enum_tys[0], + struct_enum_tys[1])); + for &next_ty in &struct_enum_tys[1..len-1] { + err.note(&format!("...which in turn is embedded within `{}`...", next_ty)); + } + err.note(&format!("...which in turn is embedded within `{}`, \ + completing the cycle.", + struct_enum_tys[len-1])); + } + err.emit(); + self.tcx.sess.abort_if_errors(); + bug!(); + } + + pub fn report_selection_error(&self, + obligation: &PredicateObligation<'tcx>, + error: &SelectionError<'tcx>, + warning_node_id: Option) + { + let span = obligation.cause.span; + let mut err = match *error { + SelectionError::Unimplemented => { + if let ObligationCauseCode::CompareImplMethodObligation = obligation.cause.code { + span_err!( + self.tcx.sess, span, E0276, + "the requirement `{}` appears on the impl \ + method but not on the corresponding trait method", + obligation.predicate); + return; + } else { + match obligation.predicate { + ty::Predicate::Trait(ref trait_predicate) => { + let trait_predicate = + self.resolve_type_vars_if_possible(trait_predicate); + + if self.tcx.sess.has_errors() && trait_predicate.references_error() { + return; + } else { + let trait_ref = trait_predicate.to_poly_trait_ref(); + + if let Some(warning_node_id) = warning_node_id { + self.tcx.sess.add_lint( + ::lint::builtin::UNSIZED_IN_TUPLE, + warning_node_id, + obligation.cause.span, + format!("the trait bound `{}` is not satisfied", + trait_ref.to_predicate())); + return; + } + + let mut err = struct_span_err!( + self.tcx.sess, span, E0277, + "the trait bound `{}` is not satisfied", + trait_ref.to_predicate()); + + // Try to report a help message + + if !trait_ref.has_infer_types() && + self.predicate_can_apply(trait_ref) + { + // If a where-clause may be useful, remind the + // user that they can add it. + // + // don't display an on-unimplemented note, as + // these notes will often be of the form + // "the type `T` can't be frobnicated" + // which is somewhat confusing. + err.help(&format!("consider adding a `where {}` bound", + trait_ref.to_predicate() + )); + } else if let Some(s) = + self.on_unimplemented_note(trait_ref, span) { + // Otherwise, if there is an on-unimplemented note, + // display it. + err.note(&s); + } else { + // If we can't show anything useful, try to find + // similar impls. + + self.report_similar_impl_candidates(trait_ref, &mut err); + } + err + } + }, + ty::Predicate::Equate(ref predicate) => { + let predicate = self.resolve_type_vars_if_possible(predicate); + let err = self.equality_predicate(span, + &predicate).err().unwrap(); + struct_span_err!(self.tcx.sess, span, E0278, + "the requirement `{}` is not satisfied (`{}`)", + predicate, err) + } + + ty::Predicate::RegionOutlives(ref predicate) => { + let predicate = self.resolve_type_vars_if_possible(predicate); + let err = self.region_outlives_predicate(span, + &predicate).err().unwrap(); + struct_span_err!(self.tcx.sess, span, E0279, + "the requirement `{}` is not satisfied (`{}`)", + predicate, err) + } + + ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => { + let predicate = + self.resolve_type_vars_if_possible(&obligation.predicate); + struct_span_err!(self.tcx.sess, span, E0280, + "the requirement `{}` is not satisfied", + predicate) + } + + ty::Predicate::ObjectSafe(trait_def_id) => { + let violations = self.tcx.object_safety_violations(trait_def_id); + let err = self.tcx.report_object_safety_error(span, + trait_def_id, + warning_node_id, + violations); + if let Some(err) = err { + err + } else { + return; + } + } + + ty::Predicate::ClosureKind(closure_def_id, kind) => { + let found_kind = self.closure_kind(closure_def_id).unwrap(); + let closure_span = self.tcx.map.span_if_local(closure_def_id).unwrap(); + let mut err = struct_span_err!( + self.tcx.sess, closure_span, E0525, + "expected a closure that implements the `{}` trait, \ + but this closure only implements `{}`", + kind, + found_kind); + err.span_note( + obligation.cause.span, + &format!("the requirement to implement \ + `{}` derives from here", kind)); + err.emit(); + return; + } + + ty::Predicate::WellFormed(ty) => { + // WF predicates cannot themselves make + // errors. They can only block due to + // ambiguity; otherwise, they always + // degenerate into other obligations + // (which may fail). + span_bug!(span, "WF predicate not satisfied for {:?}", ty); + } + + ty::Predicate::Rfc1592(ref data) => { + span_bug!( + obligation.cause.span, + "RFC1592 predicate not satisfied for {:?}", + data); + } + } + } + } + + OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, ref e) => { + let expected_trait_ref = self.resolve_type_vars_if_possible(&*expected_trait_ref); + let actual_trait_ref = self.resolve_type_vars_if_possible(&*actual_trait_ref); + if actual_trait_ref.self_ty().references_error() { + return; + } + struct_span_err!(self.tcx.sess, span, E0281, + "type mismatch: the type `{}` implements the trait `{}`, \ + but the trait `{}` is required ({})", + expected_trait_ref.self_ty(), + expected_trait_ref, + actual_trait_ref, + e) + } + + TraitNotObjectSafe(did) => { + let violations = self.tcx.object_safety_violations(did); + let err = self.tcx.report_object_safety_error(span, did, + warning_node_id, + violations); + if let Some(err) = err { + err + } else { + return; + } + } + }; + self.note_obligation_cause(&mut err, obligation); + err.emit(); + } +} + +impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { + pub fn recursive_type_with_infinite_size_error(self, + type_def_id: DefId) + -> DiagnosticBuilder<'tcx> + { + assert!(type_def_id.is_local()); + let span = self.map.span_if_local(type_def_id).unwrap(); + let mut err = struct_span_err!(self.sess, span, E0072, + "recursive type `{}` has infinite size", + self.item_path_str(type_def_id)); + err.help(&format!("insert indirection (e.g., a `Box`, `Rc`, or `&`) \ + at some point to make `{}` representable", + self.item_path_str(type_def_id))); + err + } + + pub fn report_object_safety_error(self, + span: Span, + trait_def_id: DefId, + warning_node_id: Option, + violations: Vec) + -> Option> + { + let mut err = match warning_node_id { + Some(_) => None, + None => { + Some(struct_span_err!( + self.sess, span, E0038, + "the trait `{}` cannot be made into an object", + self.item_path_str(trait_def_id))) + } + }; + + let mut reported_violations = FnvHashSet(); + for violation in violations { + if !reported_violations.insert(violation.clone()) { + continue; + } + let buf; + let note = match violation { + ObjectSafetyViolation::SizedSelf => { + "the trait cannot require that `Self : Sized`" + } + + ObjectSafetyViolation::SupertraitSelf => { + "the trait cannot use `Self` as a type parameter \ + in the supertrait listing" + } + + ObjectSafetyViolation::Method(method, + MethodViolationCode::StaticMethod) => { + buf = format!("method `{}` has no receiver", + method.name); + &buf + } + + ObjectSafetyViolation::Method(method, + MethodViolationCode::ReferencesSelf) => { + buf = format!("method `{}` references the `Self` type \ + in its arguments or return type", + method.name); + &buf + } + + ObjectSafetyViolation::Method(method, + MethodViolationCode::Generic) => { + buf = format!("method `{}` has generic type parameters", + method.name); + &buf + } + }; + match (warning_node_id, &mut err) { + (Some(node_id), &mut None) => { + self.sess.add_lint( + ::lint::builtin::OBJECT_UNSAFE_FRAGMENT, + node_id, + span, + note.to_string()); + } + (None, &mut Some(ref mut err)) => { + err.note(note); + } + _ => unreachable!() + } + } + err + } +} + +impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { + fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) { + // Unable to successfully determine, probably means + // insufficient type information, but could mean + // ambiguous impls. The latter *ought* to be a + // coherence violation, so we don't report it here. + + let predicate = self.resolve_type_vars_if_possible(&obligation.predicate); + + debug!("maybe_report_ambiguity(predicate={:?}, obligation={:?})", + predicate, + obligation); + + // Ambiguity errors are often caused as fallout from earlier + // errors. So just ignore them if this infcx is tainted. + if self.is_tainted_by_errors() { + return; + } + + match predicate { + ty::Predicate::Trait(ref data) => { + let trait_ref = data.to_poly_trait_ref(); + let self_ty = trait_ref.self_ty(); + let all_types = &trait_ref.substs().types; + if all_types.references_error() { + } else { + // Typically, this ambiguity should only happen if + // there are unresolved type inference variables + // (otherwise it would suggest a coherence + // failure). But given #21974 that is not necessarily + // the case -- we can have multiple where clauses that + // are only distinguished by a region, which results + // in an ambiguity even when all types are fully + // known, since we don't dispatch based on region + // relationships. + + // This is kind of a hack: it frequently happens that some earlier + // error prevents types from being fully inferred, and then we get + // a bunch of uninteresting errors saying something like " doesn't implement Sized". It may even be true that we + // could just skip over all checks where the self-ty is an + // inference variable, but I was afraid that there might be an + // inference variable created, registered as an obligation, and + // then never forced by writeback, and hence by skipping here we'd + // be ignoring the fact that we don't KNOW the type works + // out. Though even that would probably be harmless, given that + // we're only talking about builtin traits, which are known to be + // inhabited. But in any case I just threw in this check for + // has_errors() to be sure that compilation isn't happening + // anyway. In that case, why inundate the user. + if !self.tcx.sess.has_errors() { + if + self.tcx.lang_items.sized_trait() + .map_or(false, |sized_id| sized_id == trait_ref.def_id()) + { + self.need_type_info(obligation.cause.span, self_ty); + } else { + let mut err = struct_span_err!(self.tcx.sess, + obligation.cause.span, E0283, + "type annotations required: \ + cannot resolve `{}`", + predicate); + self.note_obligation_cause(&mut err, obligation); + err.emit(); + } + } + } + } + + ty::Predicate::WellFormed(ty) => { + // Same hacky approach as above to avoid deluging user + // with error messages. + if !ty.references_error() && !self.tcx.sess.has_errors() { + self.need_type_info(obligation.cause.span, ty); + } + } + + _ => { + if !self.tcx.sess.has_errors() { + let mut err = struct_span_err!(self.tcx.sess, + obligation.cause.span, E0284, + "type annotations required: \ + cannot resolve `{}`", + predicate); + self.note_obligation_cause(&mut err, obligation); + err.emit(); + } } } } - self.probe(|_| { - let mut selcx = SelectionContext::new(self); + /// Returns whether the trait predicate may apply for *some* assignment + /// to the type parameters. + fn predicate_can_apply(&self, pred: ty::PolyTraitRef<'tcx>) -> bool { + struct ParamToVarFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { + infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + var_map: FnvHashMap, Ty<'tcx>> + } - let cleaned_pred = pred.fold_with(&mut ParamToVarFolder { - infcx: self, - var_map: FnvHashMap() - }); + impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for ParamToVarFolder<'a, 'gcx, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.infcx.tcx } - let cleaned_pred = super::project::normalize( - &mut selcx, - ObligationCause::dummy(), - &cleaned_pred - ).value; + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + if let ty::TyParam(..) = ty.sty { + let infcx = self.infcx; + self.var_map.entry(ty).or_insert_with(|| infcx.next_ty_var()) + } else { + ty.super_fold_with(self) + } + } + } - let obligation = Obligation::new( - ObligationCause::dummy(), - cleaned_pred.to_predicate() - ); + self.probe(|_| { + let mut selcx = SelectionContext::new(self); - selcx.evaluate_obligation(&obligation) - }) -} + let cleaned_pred = pred.fold_with(&mut ParamToVarFolder { + infcx: self, + var_map: FnvHashMap() + }); + + let cleaned_pred = super::project::normalize( + &mut selcx, + ObligationCause::dummy(), + &cleaned_pred + ).value; + + let obligation = Obligation::new( + ObligationCause::dummy(), + cleaned_pred.to_predicate() + ); + + selcx.evaluate_obligation(&obligation) + }) + } -fn need_type_info(&self, span: Span, ty: Ty<'tcx>) { - span_err!(self.tcx.sess, span, E0282, - "unable to infer enough type information about `{}`; \ - type annotations or generic parameter binding required", - ty); -} + fn need_type_info(&self, span: Span, ty: Ty<'tcx>) { + span_err!(self.tcx.sess, span, E0282, + "unable to infer enough type information about `{}`; \ + type annotations or generic parameter binding required", + ty); + } -fn note_obligation_cause(&self, - err: &mut DiagnosticBuilder, - obligation: &Obligation<'tcx, T>) - where T: fmt::Display -{ - self.note_obligation_cause_code(err, - &obligation.predicate, - &obligation.cause.code); -} + fn note_obligation_cause(&self, + err: &mut DiagnosticBuilder, + obligation: &Obligation<'tcx, T>) + where T: fmt::Display + { + self.note_obligation_cause_code(err, + &obligation.predicate, + &obligation.cause.code); + } -fn note_obligation_cause_code(&self, - err: &mut DiagnosticBuilder, - predicate: &T, - cause_code: &ObligationCauseCode<'tcx>) - where T: fmt::Display -{ - let tcx = self.tcx; - match *cause_code { - ObligationCauseCode::MiscObligation => { } - ObligationCauseCode::SliceOrArrayElem => { - err.note("slice and array elements must have `Sized` type"); - } - ObligationCauseCode::TupleElem => { - err.note("tuple elements must have `Sized` type"); - } - ObligationCauseCode::ProjectionWf(data) => { - err.note(&format!("required so that the projection `{}` is well-formed", - data)); - } - ObligationCauseCode::ReferenceOutlivesReferent(ref_ty) => { - err.note(&format!("required so that reference `{}` does not outlive its referent", - ref_ty)); - } - ObligationCauseCode::ItemObligation(item_def_id) => { - let item_name = tcx.item_path_str(item_def_id); - err.note(&format!("required by `{}`", item_name)); - } - ObligationCauseCode::ObjectCastObligation(object_ty) => { - err.note(&format!("required for the cast to the object type `{}`", - self.ty_to_string(object_ty))); - } - ObligationCauseCode::RepeatVec => { - err.note("the `Copy` trait is required because the \ - repeated element will be copied"); - } - ObligationCauseCode::VariableType(_) => { - err.note("all local variables must have a statically known size"); - } - ObligationCauseCode::ReturnType => { - err.note("the return type of a function must have a \ - statically known size"); - } - ObligationCauseCode::AssignmentLhsSized => { - err.note("the left-hand-side of an assignment must have a statically known size"); - } - ObligationCauseCode::StructInitializerSized => { - err.note("structs must have a statically known size to be initialized"); - } - ObligationCauseCode::ClosureCapture(var_id, _, builtin_bound) => { - let def_id = tcx.lang_items.from_builtin_kind(builtin_bound).unwrap(); - let trait_name = tcx.item_path_str(def_id); - let name = tcx.local_var_name_str(var_id); - err.note( - &format!("the closure that captures `{}` requires that all captured variables \ - implement the trait `{}`", - name, - trait_name)); - } - ObligationCauseCode::FieldSized => { - err.note("only the last field of a struct or enum variant \ - may have a dynamically sized type"); - } - ObligationCauseCode::SharedStatic => { - err.note("shared static variables must have a type that implements `Sync`"); - } - ObligationCauseCode::BuiltinDerivedObligation(ref data) => { - let parent_trait_ref = self.resolve_type_vars_if_possible(&data.parent_trait_ref); - err.note(&format!("required because it appears within the type `{}`", - parent_trait_ref.0.self_ty())); - let parent_predicate = parent_trait_ref.to_predicate(); - self.note_obligation_cause_code(err, - &parent_predicate, - &data.parent_code); - } - ObligationCauseCode::ImplDerivedObligation(ref data) => { - let parent_trait_ref = self.resolve_type_vars_if_possible(&data.parent_trait_ref); - err.note( - &format!("required because of the requirements on the impl of `{}` for `{}`", - parent_trait_ref, - parent_trait_ref.0.self_ty())); - let parent_predicate = parent_trait_ref.to_predicate(); - self.note_obligation_cause_code(err, - &parent_predicate, - &data.parent_code); - } - ObligationCauseCode::CompareImplMethodObligation => { - err.note( - &format!("the requirement `{}` appears on the impl method \ - but not on the corresponding trait method", - predicate)); + fn note_obligation_cause_code(&self, + err: &mut DiagnosticBuilder, + predicate: &T, + cause_code: &ObligationCauseCode<'tcx>) + where T: fmt::Display + { + let tcx = self.tcx; + match *cause_code { + ObligationCauseCode::MiscObligation => { } + ObligationCauseCode::SliceOrArrayElem => { + err.note("slice and array elements must have `Sized` type"); + } + ObligationCauseCode::TupleElem => { + err.note("tuple elements must have `Sized` type"); + } + ObligationCauseCode::ProjectionWf(data) => { + err.note(&format!("required so that the projection `{}` is well-formed", + data)); + } + ObligationCauseCode::ReferenceOutlivesReferent(ref_ty) => { + err.note(&format!("required so that reference `{}` does not outlive its referent", + ref_ty)); + } + ObligationCauseCode::ItemObligation(item_def_id) => { + let item_name = tcx.item_path_str(item_def_id); + err.note(&format!("required by `{}`", item_name)); + } + ObligationCauseCode::ObjectCastObligation(object_ty) => { + err.note(&format!("required for the cast to the object type `{}`", + self.ty_to_string(object_ty))); + } + ObligationCauseCode::RepeatVec => { + err.note("the `Copy` trait is required because the \ + repeated element will be copied"); + } + ObligationCauseCode::VariableType(_) => { + err.note("all local variables must have a statically known size"); + } + ObligationCauseCode::ReturnType => { + err.note("the return type of a function must have a \ + statically known size"); + } + ObligationCauseCode::AssignmentLhsSized => { + err.note("the left-hand-side of an assignment must have a statically known size"); + } + ObligationCauseCode::StructInitializerSized => { + err.note("structs must have a statically known size to be initialized"); + } + ObligationCauseCode::ClosureCapture(var_id, _, builtin_bound) => { + let def_id = tcx.lang_items.from_builtin_kind(builtin_bound).unwrap(); + let trait_name = tcx.item_path_str(def_id); + let name = tcx.local_var_name_str(var_id); + err.note( + &format!("the closure that captures `{}` requires that all captured variables \ + implement the trait `{}`", + name, + trait_name)); + } + ObligationCauseCode::FieldSized => { + err.note("only the last field of a struct or enum variant \ + may have a dynamically sized type"); + } + ObligationCauseCode::SharedStatic => { + err.note("shared static variables must have a type that implements `Sync`"); + } + ObligationCauseCode::BuiltinDerivedObligation(ref data) => { + let parent_trait_ref = self.resolve_type_vars_if_possible(&data.parent_trait_ref); + err.note(&format!("required because it appears within the type `{}`", + parent_trait_ref.0.self_ty())); + let parent_predicate = parent_trait_ref.to_predicate(); + self.note_obligation_cause_code(err, + &parent_predicate, + &data.parent_code); + } + ObligationCauseCode::ImplDerivedObligation(ref data) => { + let parent_trait_ref = self.resolve_type_vars_if_possible(&data.parent_trait_ref); + err.note( + &format!("required because of the requirements on the impl of `{}` for `{}`", + parent_trait_ref, + parent_trait_ref.0.self_ty())); + let parent_predicate = parent_trait_ref.to_predicate(); + self.note_obligation_cause_code(err, + &parent_predicate, + &data.parent_code); + } + ObligationCauseCode::CompareImplMethodObligation => { + err.note( + &format!("the requirement `{}` appears on the impl method \ + but not on the corresponding trait method", + predicate)); + } } } -} -fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder) { - let current_limit = self.tcx.sess.recursion_limit.get(); - let suggested_limit = current_limit * 2; - err.note(&format!( - "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", - suggested_limit)); -} + fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder) { + let current_limit = self.tcx.sess.recursion_limit.get(); + let suggested_limit = current_limit * 2; + err.note(&format!( + "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", + suggested_limit)); + } } diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 8fffe3fa666..8cafa779739 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -54,320 +54,320 @@ pub enum MethodViolationCode { } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { -pub fn is_object_safe(self, trait_def_id: DefId) -> bool { - // Because we query yes/no results frequently, we keep a cache: - let def = self.lookup_trait_def(trait_def_id); + pub fn is_object_safe(self, trait_def_id: DefId) -> bool { + // Because we query yes/no results frequently, we keep a cache: + let def = self.lookup_trait_def(trait_def_id); - let result = def.object_safety().unwrap_or_else(|| { - let result = self.object_safety_violations(trait_def_id).is_empty(); + let result = def.object_safety().unwrap_or_else(|| { + let result = self.object_safety_violations(trait_def_id).is_empty(); - // Record just a yes/no result in the cache; this is what is - // queried most frequently. Note that this may overwrite a - // previous result, but always with the same thing. - def.set_object_safety(result); + // Record just a yes/no result in the cache; this is what is + // queried most frequently. Note that this may overwrite a + // previous result, but always with the same thing. + def.set_object_safety(result); + + result + }); + + debug!("is_object_safe({:?}) = {}", trait_def_id, result); result - }); - - debug!("is_object_safe({:?}) = {}", trait_def_id, result); - - result -} - -/// Returns the object safety violations that affect -/// astconv - currently, Self in supertraits. This is needed -/// because `object_safety_violations` can't be used during -/// type collection. -pub fn astconv_object_safety_violations(self, trait_def_id: DefId) - -> Vec> -{ - let mut violations = vec![]; - - if self.supertraits_reference_self(trait_def_id) { - violations.push(ObjectSafetyViolation::SupertraitSelf); } - debug!("astconv_object_safety_violations(trait_def_id={:?}) = {:?}", - trait_def_id, - violations); + /// Returns the object safety violations that affect + /// astconv - currently, Self in supertraits. This is needed + /// because `object_safety_violations` can't be used during + /// type collection. + pub fn astconv_object_safety_violations(self, trait_def_id: DefId) + -> Vec> + { + let mut violations = vec![]; - violations -} - -pub fn object_safety_violations(self, trait_def_id: DefId) - -> Vec> -{ - traits::supertrait_def_ids(self, trait_def_id) - .flat_map(|def_id| self.object_safety_violations_for_trait(def_id)) - .collect() -} - -fn object_safety_violations_for_trait(self, trait_def_id: DefId) - -> Vec> -{ - // Check methods for violations. - let mut violations: Vec<_> = - self.trait_items(trait_def_id).iter() - .filter_map(|item| { - match *item { - ty::MethodTraitItem(ref m) => { - self.object_safety_violation_for_method(trait_def_id, &m) - .map(|code| ObjectSafetyViolation::Method(m.clone(), code)) - } - _ => None, - } - }) - .collect(); - - // Check the trait itself. - if self.trait_has_sized_self(trait_def_id) { - violations.push(ObjectSafetyViolation::SizedSelf); - } - if self.supertraits_reference_self(trait_def_id) { - violations.push(ObjectSafetyViolation::SupertraitSelf); - } - - debug!("object_safety_violations_for_trait(trait_def_id={:?}) = {:?}", - trait_def_id, - violations); - - violations -} - -fn supertraits_reference_self(self, trait_def_id: DefId) -> bool { - let trait_def = self.lookup_trait_def(trait_def_id); - let trait_ref = trait_def.trait_ref.clone(); - let trait_ref = trait_ref.to_poly_trait_ref(); - let predicates = self.lookup_super_predicates(trait_def_id); - predicates - .predicates - .into_iter() - .map(|predicate| predicate.subst_supertrait(self, &trait_ref)) - .any(|predicate| { - match predicate { - ty::Predicate::Trait(ref data) => { - // In the case of a trait predicate, we can skip the "self" type. - data.0.trait_ref.substs.types.get_slice(TypeSpace) - .iter() - .cloned() - .any(|t| t.has_self_ty()) - } - ty::Predicate::Projection(..) | - ty::Predicate::WellFormed(..) | - ty::Predicate::ObjectSafe(..) | - ty::Predicate::TypeOutlives(..) | - ty::Predicate::RegionOutlives(..) | - ty::Predicate::ClosureKind(..) | - ty::Predicate::Rfc1592(..) | - ty::Predicate::Equate(..) => { - false - } - } - }) -} - -fn trait_has_sized_self(self, trait_def_id: DefId) -> bool { - let trait_def = self.lookup_trait_def(trait_def_id); - let trait_predicates = self.lookup_predicates(trait_def_id); - self.generics_require_sized_self(&trait_def.generics, &trait_predicates) -} - -fn generics_require_sized_self(self, - generics: &ty::Generics<'gcx>, - predicates: &ty::GenericPredicates<'gcx>) - -> bool -{ - let sized_def_id = match self.lang_items.sized_trait() { - Some(def_id) => def_id, - None => { return false; /* No Sized trait, can't require it! */ } - }; - - // Search for a predicate like `Self : Sized` amongst the trait bounds. - let free_substs = self.construct_free_substs(generics, - self.region_maps.node_extent(ast::DUMMY_NODE_ID)); - let predicates = predicates.instantiate(self, &free_substs).predicates.into_vec(); - elaborate_predicates(self, predicates) - .any(|predicate| { - match predicate { - ty::Predicate::Trait(ref trait_pred) if trait_pred.def_id() == sized_def_id => { - trait_pred.0.self_ty().is_self() - } - ty::Predicate::Projection(..) | - ty::Predicate::Trait(..) | - ty::Predicate::Rfc1592(..) | - ty::Predicate::Equate(..) | - ty::Predicate::RegionOutlives(..) | - ty::Predicate::WellFormed(..) | - ty::Predicate::ObjectSafe(..) | - ty::Predicate::ClosureKind(..) | - ty::Predicate::TypeOutlives(..) => { - false - } - } - }) -} - -/// Returns `Some(_)` if this method makes the containing trait not object safe. -fn object_safety_violation_for_method(self, - trait_def_id: DefId, - method: &ty::Method<'gcx>) - -> Option -{ - // Any method that has a `Self : Sized` requisite is otherwise - // exempt from the regulations. - if self.generics_require_sized_self(&method.generics, &method.predicates) { - return None; - } - - self.virtual_call_violation_for_method(trait_def_id, method) -} - -/// We say a method is *vtable safe* if it can be invoked on a trait -/// object. Note that object-safe traits can have some -/// non-vtable-safe methods, so long as they require `Self:Sized` or -/// otherwise ensure that they cannot be used when `Self=Trait`. -pub fn is_vtable_safe_method(self, - trait_def_id: DefId, - method: &ty::Method<'tcx>) - -> bool -{ - self.virtual_call_violation_for_method(trait_def_id, method).is_none() -} - -/// Returns `Some(_)` if this method cannot be called on a trait -/// object; this does not necessarily imply that the enclosing trait -/// is not object safe, because the method might have a where clause -/// `Self:Sized`. -fn virtual_call_violation_for_method(self, - trait_def_id: DefId, - method: &ty::Method<'tcx>) - -> Option -{ - // The method's first parameter must be something that derefs (or - // autorefs) to `&self`. For now, we only accept `self`, `&self` - // and `Box`. - match method.explicit_self { - ty::ExplicitSelfCategory::Static => { - return Some(MethodViolationCode::StaticMethod); + if self.supertraits_reference_self(trait_def_id) { + violations.push(ObjectSafetyViolation::SupertraitSelf); } - ty::ExplicitSelfCategory::ByValue | - ty::ExplicitSelfCategory::ByReference(..) | - ty::ExplicitSelfCategory::ByBox => { - } + debug!("astconv_object_safety_violations(trait_def_id={:?}) = {:?}", + trait_def_id, + violations); + + violations } - // The `Self` type is erased, so it should not appear in list of - // arguments or return type apart from the receiver. - let ref sig = method.fty.sig; - for &input_ty in &sig.0.inputs[1..] { - if self.contains_illegal_self_type_reference(trait_def_id, input_ty) { - return Some(MethodViolationCode::ReferencesSelf); - } - } - if let ty::FnConverging(result_type) = sig.0.output { - if self.contains_illegal_self_type_reference(trait_def_id, result_type) { - return Some(MethodViolationCode::ReferencesSelf); - } + pub fn object_safety_violations(self, trait_def_id: DefId) + -> Vec> + { + traits::supertrait_def_ids(self, trait_def_id) + .flat_map(|def_id| self.object_safety_violations_for_trait(def_id)) + .collect() } - // We can't monomorphize things like `fn foo(...)`. - if !method.generics.types.is_empty_in(subst::FnSpace) { - return Some(MethodViolationCode::Generic); - } - - None -} - -fn contains_illegal_self_type_reference(self, - trait_def_id: DefId, - ty: Ty<'tcx>) - -> bool -{ - // This is somewhat subtle. In general, we want to forbid - // references to `Self` in the argument and return types, - // since the value of `Self` is erased. However, there is one - // exception: it is ok to reference `Self` in order to access - // an associated type of the current trait, since we retain - // the value of those associated types in the object type - // itself. - // - // ```rust - // trait SuperTrait { - // type X; - // } - // - // trait Trait : SuperTrait { - // type Y; - // fn foo(&self, x: Self) // bad - // fn foo(&self) -> Self // bad - // fn foo(&self) -> Option // bad - // fn foo(&self) -> Self::Y // OK, desugars to next example - // fn foo(&self) -> ::Y // OK - // fn foo(&self) -> Self::X // OK, desugars to next example - // fn foo(&self) -> ::X // OK - // } - // ``` - // - // However, it is not as simple as allowing `Self` in a projected - // type, because there are illegal ways to use `Self` as well: - // - // ```rust - // trait Trait : SuperTrait { - // ... - // fn foo(&self) -> ::X; - // } - // ``` - // - // Here we will not have the type of `X` recorded in the - // object type, and we cannot resolve `Self as SomeOtherTrait` - // without knowing what `Self` is. - - let mut supertraits: Option>> = None; - let mut error = false; - ty.maybe_walk(|ty| { - match ty.sty { - ty::TyParam(ref param_ty) => { - if param_ty.space == SelfSpace { - error = true; + fn object_safety_violations_for_trait(self, trait_def_id: DefId) + -> Vec> + { + // Check methods for violations. + let mut violations: Vec<_> = + self.trait_items(trait_def_id).iter() + .filter_map(|item| { + match *item { + ty::MethodTraitItem(ref m) => { + self.object_safety_violation_for_method(trait_def_id, &m) + .map(|code| ObjectSafetyViolation::Method(m.clone(), code)) + } + _ => None, } + }) + .collect(); - false // no contained types to walk + // Check the trait itself. + if self.trait_has_sized_self(trait_def_id) { + violations.push(ObjectSafetyViolation::SizedSelf); + } + if self.supertraits_reference_self(trait_def_id) { + violations.push(ObjectSafetyViolation::SupertraitSelf); + } + + debug!("object_safety_violations_for_trait(trait_def_id={:?}) = {:?}", + trait_def_id, + violations); + + violations + } + + fn supertraits_reference_self(self, trait_def_id: DefId) -> bool { + let trait_def = self.lookup_trait_def(trait_def_id); + let trait_ref = trait_def.trait_ref.clone(); + let trait_ref = trait_ref.to_poly_trait_ref(); + let predicates = self.lookup_super_predicates(trait_def_id); + predicates + .predicates + .into_iter() + .map(|predicate| predicate.subst_supertrait(self, &trait_ref)) + .any(|predicate| { + match predicate { + ty::Predicate::Trait(ref data) => { + // In the case of a trait predicate, we can skip the "self" type. + data.0.trait_ref.substs.types.get_slice(TypeSpace) + .iter() + .cloned() + .any(|t| t.has_self_ty()) + } + ty::Predicate::Projection(..) | + ty::Predicate::WellFormed(..) | + ty::Predicate::ObjectSafe(..) | + ty::Predicate::TypeOutlives(..) | + ty::Predicate::RegionOutlives(..) | + ty::Predicate::ClosureKind(..) | + ty::Predicate::Rfc1592(..) | + ty::Predicate::Equate(..) => { + false + } + } + }) + } + + fn trait_has_sized_self(self, trait_def_id: DefId) -> bool { + let trait_def = self.lookup_trait_def(trait_def_id); + let trait_predicates = self.lookup_predicates(trait_def_id); + self.generics_require_sized_self(&trait_def.generics, &trait_predicates) + } + + fn generics_require_sized_self(self, + generics: &ty::Generics<'gcx>, + predicates: &ty::GenericPredicates<'gcx>) + -> bool + { + let sized_def_id = match self.lang_items.sized_trait() { + Some(def_id) => def_id, + None => { return false; /* No Sized trait, can't require it! */ } + }; + + // Search for a predicate like `Self : Sized` amongst the trait bounds. + let free_substs = self.construct_free_substs(generics, + self.region_maps.node_extent(ast::DUMMY_NODE_ID)); + let predicates = predicates.instantiate(self, &free_substs).predicates.into_vec(); + elaborate_predicates(self, predicates) + .any(|predicate| { + match predicate { + ty::Predicate::Trait(ref trait_pred) if trait_pred.def_id() == sized_def_id => { + trait_pred.0.self_ty().is_self() + } + ty::Predicate::Projection(..) | + ty::Predicate::Trait(..) | + ty::Predicate::Rfc1592(..) | + ty::Predicate::Equate(..) | + ty::Predicate::RegionOutlives(..) | + ty::Predicate::WellFormed(..) | + ty::Predicate::ObjectSafe(..) | + ty::Predicate::ClosureKind(..) | + ty::Predicate::TypeOutlives(..) => { + false + } + } + }) + } + + /// Returns `Some(_)` if this method makes the containing trait not object safe. + fn object_safety_violation_for_method(self, + trait_def_id: DefId, + method: &ty::Method<'gcx>) + -> Option + { + // Any method that has a `Self : Sized` requisite is otherwise + // exempt from the regulations. + if self.generics_require_sized_self(&method.generics, &method.predicates) { + return None; + } + + self.virtual_call_violation_for_method(trait_def_id, method) + } + + /// We say a method is *vtable safe* if it can be invoked on a trait + /// object. Note that object-safe traits can have some + /// non-vtable-safe methods, so long as they require `Self:Sized` or + /// otherwise ensure that they cannot be used when `Self=Trait`. + pub fn is_vtable_safe_method(self, + trait_def_id: DefId, + method: &ty::Method<'tcx>) + -> bool + { + self.virtual_call_violation_for_method(trait_def_id, method).is_none() + } + + /// Returns `Some(_)` if this method cannot be called on a trait + /// object; this does not necessarily imply that the enclosing trait + /// is not object safe, because the method might have a where clause + /// `Self:Sized`. + fn virtual_call_violation_for_method(self, + trait_def_id: DefId, + method: &ty::Method<'tcx>) + -> Option + { + // The method's first parameter must be something that derefs (or + // autorefs) to `&self`. For now, we only accept `self`, `&self` + // and `Box`. + match method.explicit_self { + ty::ExplicitSelfCategory::Static => { + return Some(MethodViolationCode::StaticMethod); } - ty::TyProjection(ref data) => { - // This is a projected type `::X`. - - // Compute supertraits of current trait lazily. - if supertraits.is_none() { - let trait_def = self.lookup_trait_def(trait_def_id); - let trait_ref = ty::Binder(trait_def.trait_ref.clone()); - supertraits = Some(traits::supertraits(self, trait_ref).collect()); - } - - // Determine whether the trait reference `Foo as - // SomeTrait` is in fact a supertrait of the - // current trait. In that case, this type is - // legal, because the type `X` will be specified - // in the object type. Note that we can just use - // direct equality here because all of these types - // are part of the formal parameter listing, and - // hence there should be no inference variables. - let projection_trait_ref = ty::Binder(data.trait_ref.clone()); - let is_supertrait_of_current_trait = - supertraits.as_ref().unwrap().contains(&projection_trait_ref); - - if is_supertrait_of_current_trait { - false // do not walk contained types, do not report error, do collect $200 - } else { - true // DO walk contained types, POSSIBLY reporting an error - } + ty::ExplicitSelfCategory::ByValue | + ty::ExplicitSelfCategory::ByReference(..) | + ty::ExplicitSelfCategory::ByBox => { } - - _ => true, // walk contained types, if any } - }); - error -} + // The `Self` type is erased, so it should not appear in list of + // arguments or return type apart from the receiver. + let ref sig = method.fty.sig; + for &input_ty in &sig.0.inputs[1..] { + if self.contains_illegal_self_type_reference(trait_def_id, input_ty) { + return Some(MethodViolationCode::ReferencesSelf); + } + } + if let ty::FnConverging(result_type) = sig.0.output { + if self.contains_illegal_self_type_reference(trait_def_id, result_type) { + return Some(MethodViolationCode::ReferencesSelf); + } + } + + // We can't monomorphize things like `fn foo(...)`. + if !method.generics.types.is_empty_in(subst::FnSpace) { + return Some(MethodViolationCode::Generic); + } + + None + } + + fn contains_illegal_self_type_reference(self, + trait_def_id: DefId, + ty: Ty<'tcx>) + -> bool + { + // This is somewhat subtle. In general, we want to forbid + // references to `Self` in the argument and return types, + // since the value of `Self` is erased. However, there is one + // exception: it is ok to reference `Self` in order to access + // an associated type of the current trait, since we retain + // the value of those associated types in the object type + // itself. + // + // ```rust + // trait SuperTrait { + // type X; + // } + // + // trait Trait : SuperTrait { + // type Y; + // fn foo(&self, x: Self) // bad + // fn foo(&self) -> Self // bad + // fn foo(&self) -> Option // bad + // fn foo(&self) -> Self::Y // OK, desugars to next example + // fn foo(&self) -> ::Y // OK + // fn foo(&self) -> Self::X // OK, desugars to next example + // fn foo(&self) -> ::X // OK + // } + // ``` + // + // However, it is not as simple as allowing `Self` in a projected + // type, because there are illegal ways to use `Self` as well: + // + // ```rust + // trait Trait : SuperTrait { + // ... + // fn foo(&self) -> ::X; + // } + // ``` + // + // Here we will not have the type of `X` recorded in the + // object type, and we cannot resolve `Self as SomeOtherTrait` + // without knowing what `Self` is. + + let mut supertraits: Option>> = None; + let mut error = false; + ty.maybe_walk(|ty| { + match ty.sty { + ty::TyParam(ref param_ty) => { + if param_ty.space == SelfSpace { + error = true; + } + + false // no contained types to walk + } + + ty::TyProjection(ref data) => { + // This is a projected type `::X`. + + // Compute supertraits of current trait lazily. + if supertraits.is_none() { + let trait_def = self.lookup_trait_def(trait_def_id); + let trait_ref = ty::Binder(trait_def.trait_ref.clone()); + supertraits = Some(traits::supertraits(self, trait_ref).collect()); + } + + // Determine whether the trait reference `Foo as + // SomeTrait` is in fact a supertrait of the + // current trait. In that case, this type is + // legal, because the type `X` will be specified + // in the object type. Note that we can just use + // direct equality here because all of these types + // are part of the formal parameter listing, and + // hence there should be no inference variables. + let projection_trait_ref = ty::Binder(data.trait_ref.clone()); + let is_supertrait_of_current_trait = + supertraits.as_ref().unwrap().contains(&projection_trait_ref); + + if is_supertrait_of_current_trait { + false // do not walk contained types, do not report error, do collect $200 + } else { + true // DO walk contained types, POSSIBLY reporting an error + } + } + + _ => true, // walk contained types, if any + } + }); + + error + } } diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 55fb8beee01..010add01237 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -393,130 +393,130 @@ pub fn predicate_for_trait_ref<'tcx>( } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { -pub fn trait_ref_for_builtin_bound(self, - builtin_bound: ty::BuiltinBound, - param_ty: Ty<'tcx>) - -> Result, ErrorReported> -{ - match self.lang_items.from_builtin_kind(builtin_bound) { - Ok(def_id) => { - Ok(ty::TraitRef { - def_id: def_id, - substs: self.mk_substs(Substs::empty().with_self_ty(param_ty)) - }) - } - Err(e) => { - self.sess.err(&e); - Err(ErrorReported) - } - } -} - -pub fn predicate_for_trait_def(self, - cause: ObligationCause<'tcx>, - trait_def_id: DefId, - recursion_depth: usize, - param_ty: Ty<'tcx>, - ty_params: Vec>) - -> PredicateObligation<'tcx> -{ - let trait_ref = ty::TraitRef { - def_id: trait_def_id, - substs: self.mk_substs(Substs::new_trait(ty_params, vec![], param_ty)) - }; - predicate_for_trait_ref(cause, trait_ref, recursion_depth) -} - -pub fn predicate_for_builtin_bound(self, - cause: ObligationCause<'tcx>, - builtin_bound: ty::BuiltinBound, - recursion_depth: usize, - param_ty: Ty<'tcx>) - -> Result, ErrorReported> -{ - let trait_ref = self.trait_ref_for_builtin_bound(builtin_bound, param_ty)?; - Ok(predicate_for_trait_ref(cause, trait_ref, recursion_depth)) -} - -/// Cast a trait reference into a reference to one of its super -/// traits; returns `None` if `target_trait_def_id` is not a -/// supertrait. -pub fn upcast_choices(self, - source_trait_ref: ty::PolyTraitRef<'tcx>, - target_trait_def_id: DefId) - -> Vec> -{ - if source_trait_ref.def_id() == target_trait_def_id { - return vec![source_trait_ref]; // shorcut the most common case - } - - supertraits(self, source_trait_ref) - .filter(|r| r.def_id() == target_trait_def_id) - .collect() -} - -/// Given a trait `trait_ref`, returns the number of vtable entries -/// that come from `trait_ref`, excluding its supertraits. Used in -/// computing the vtable base for an upcast trait of a trait object. -pub fn count_own_vtable_entries(self, trait_ref: ty::PolyTraitRef<'tcx>) -> usize { - let mut entries = 0; - // Count number of methods and add them to the total offset. - // Skip over associated types and constants. - for trait_item in &self.trait_items(trait_ref.def_id())[..] { - if let ty::MethodTraitItem(_) = *trait_item { - entries += 1; - } - } - entries -} - -/// Given an upcast trait object described by `object`, returns the -/// index of the method `method_def_id` (which should be part of -/// `object.upcast_trait_ref`) within the vtable for `object`. -pub fn get_vtable_index_of_object_method(self, - object: &super::VtableObjectData<'tcx>, - method_def_id: DefId) -> usize { - // Count number of methods preceding the one we are selecting and - // add them to the total offset. - // Skip over associated types and constants. - let mut entries = object.vtable_base; - for trait_item in &self.trait_items(object.upcast_trait_ref.def_id())[..] { - if trait_item.def_id() == method_def_id { - // The item with the ID we were given really ought to be a method. - assert!(match *trait_item { - ty::MethodTraitItem(_) => true, - _ => false - }); - - return entries; - } - if let ty::MethodTraitItem(_) = *trait_item { - entries += 1; + pub fn trait_ref_for_builtin_bound(self, + builtin_bound: ty::BuiltinBound, + param_ty: Ty<'tcx>) + -> Result, ErrorReported> + { + match self.lang_items.from_builtin_kind(builtin_bound) { + Ok(def_id) => { + Ok(ty::TraitRef { + def_id: def_id, + substs: self.mk_substs(Substs::empty().with_self_ty(param_ty)) + }) + } + Err(e) => { + self.sess.err(&e); + Err(ErrorReported) + } } } - bug!("get_vtable_index_of_object_method: {:?} was not found", - method_def_id); -} + pub fn predicate_for_trait_def(self, + cause: ObligationCause<'tcx>, + trait_def_id: DefId, + recursion_depth: usize, + param_ty: Ty<'tcx>, + ty_params: Vec>) + -> PredicateObligation<'tcx> + { + let trait_ref = ty::TraitRef { + def_id: trait_def_id, + substs: self.mk_substs(Substs::new_trait(ty_params, vec![], param_ty)) + }; + predicate_for_trait_ref(cause, trait_ref, recursion_depth) + } -pub fn closure_trait_ref_and_return_type(self, - fn_trait_def_id: DefId, - self_ty: Ty<'tcx>, - sig: &ty::PolyFnSig<'tcx>, - tuple_arguments: TupleArgumentsFlag) - -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>)> -{ - let arguments_tuple = match tuple_arguments { - TupleArgumentsFlag::No => sig.0.inputs[0], - TupleArgumentsFlag::Yes => self.mk_tup(sig.0.inputs.to_vec()), - }; - let trait_substs = Substs::new_trait(vec![arguments_tuple], vec![], self_ty); - let trait_ref = ty::TraitRef { - def_id: fn_trait_def_id, - substs: self.mk_substs(trait_substs), - }; - ty::Binder((trait_ref, sig.0.output.unwrap_or(self.mk_nil()))) -} + pub fn predicate_for_builtin_bound(self, + cause: ObligationCause<'tcx>, + builtin_bound: ty::BuiltinBound, + recursion_depth: usize, + param_ty: Ty<'tcx>) + -> Result, ErrorReported> + { + let trait_ref = self.trait_ref_for_builtin_bound(builtin_bound, param_ty)?; + Ok(predicate_for_trait_ref(cause, trait_ref, recursion_depth)) + } + + /// Cast a trait reference into a reference to one of its super + /// traits; returns `None` if `target_trait_def_id` is not a + /// supertrait. + pub fn upcast_choices(self, + source_trait_ref: ty::PolyTraitRef<'tcx>, + target_trait_def_id: DefId) + -> Vec> + { + if source_trait_ref.def_id() == target_trait_def_id { + return vec![source_trait_ref]; // shorcut the most common case + } + + supertraits(self, source_trait_ref) + .filter(|r| r.def_id() == target_trait_def_id) + .collect() + } + + /// Given a trait `trait_ref`, returns the number of vtable entries + /// that come from `trait_ref`, excluding its supertraits. Used in + /// computing the vtable base for an upcast trait of a trait object. + pub fn count_own_vtable_entries(self, trait_ref: ty::PolyTraitRef<'tcx>) -> usize { + let mut entries = 0; + // Count number of methods and add them to the total offset. + // Skip over associated types and constants. + for trait_item in &self.trait_items(trait_ref.def_id())[..] { + if let ty::MethodTraitItem(_) = *trait_item { + entries += 1; + } + } + entries + } + + /// Given an upcast trait object described by `object`, returns the + /// index of the method `method_def_id` (which should be part of + /// `object.upcast_trait_ref`) within the vtable for `object`. + pub fn get_vtable_index_of_object_method(self, + object: &super::VtableObjectData<'tcx>, + method_def_id: DefId) -> usize { + // Count number of methods preceding the one we are selecting and + // add them to the total offset. + // Skip over associated types and constants. + let mut entries = object.vtable_base; + for trait_item in &self.trait_items(object.upcast_trait_ref.def_id())[..] { + if trait_item.def_id() == method_def_id { + // The item with the ID we were given really ought to be a method. + assert!(match *trait_item { + ty::MethodTraitItem(_) => true, + _ => false + }); + + return entries; + } + if let ty::MethodTraitItem(_) = *trait_item { + entries += 1; + } + } + + bug!("get_vtable_index_of_object_method: {:?} was not found", + method_def_id); + } + + pub fn closure_trait_ref_and_return_type(self, + fn_trait_def_id: DefId, + self_ty: Ty<'tcx>, + sig: &ty::PolyFnSig<'tcx>, + tuple_arguments: TupleArgumentsFlag) + -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>)> + { + let arguments_tuple = match tuple_arguments { + TupleArgumentsFlag::No => sig.0.inputs[0], + TupleArgumentsFlag::Yes => self.mk_tup(sig.0.inputs.to_vec()), + }; + let trait_substs = Substs::new_trait(vec![arguments_tuple], vec![], self_ty); + let trait_ref = ty::TraitRef { + def_id: fn_trait_def_id, + substs: self.mk_substs(trait_substs), + }; + ty::Binder((trait_ref, sig.0.output.unwrap_or(self.mk_nil()))) + } } pub enum TupleArgumentsFlag { Yes, No } diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index 60f8f277d39..9ae3325c258 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -56,156 +56,156 @@ pub enum Component<'tcx> { } impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { -/// Returns all the things that must outlive `'a` for the condition -/// `ty0: 'a` to hold. -pub fn outlives_components(&self, ty0: Ty<'tcx>) - -> Vec> { - let mut components = vec![]; - self.compute_components(ty0, &mut components); - debug!("components({:?}) = {:?}", ty0, components); - components -} + /// Returns all the things that must outlive `'a` for the condition + /// `ty0: 'a` to hold. + pub fn outlives_components(&self, ty0: Ty<'tcx>) + -> Vec> { + let mut components = vec![]; + self.compute_components(ty0, &mut components); + debug!("components({:?}) = {:?}", ty0, components); + components + } -fn compute_components(&self, ty: Ty<'tcx>, out: &mut Vec>) { - // Descend through the types, looking for the various "base" - // components and collecting them into `out`. This is not written - // with `collect()` because of the need to sometimes skip subtrees - // in the `subtys` iterator (e.g., when encountering a - // projection). - match ty.sty { - ty::TyClosure(_, ref substs) => { - // FIXME(#27086). We do not accumulate from substs, since they - // don't represent reachable data. This means that, in - // practice, some of the lifetime parameters might not - // be in scope when the body runs, so long as there is - // no reachable data with that lifetime. For better or - // worse, this is consistent with fn types, however, - // which can also encapsulate data in this fashion - // (though it's somewhat harder, and typically - // requires virtual dispatch). - // - // Note that changing this (in a naive way, at least) - // causes regressions for what appears to be perfectly - // reasonable code like this: - // - // ``` - // fn foo<'a>(p: &Data<'a>) { - // bar(|q: &mut Parser| q.read_addr()) - // } - // fn bar(p: Box) { - // } - // ``` - // - // Note that `p` (and `'a`) are not used in the - // closure at all, but to meet the requirement that - // the closure type `C: 'static` (so it can be coerced - // to the object type), we get the requirement that - // `'a: 'static` since `'a` appears in the closure - // type `C`. - // - // A smarter fix might "prune" unused `func_substs` -- - // this would avoid breaking simple examples like - // this, but would still break others (which might - // indeed be invalid, depending on your POV). Pruning - // would be a subtle process, since we have to see - // what func/type parameters are used and unused, - // taking into consideration UFCS and so forth. + fn compute_components(&self, ty: Ty<'tcx>, out: &mut Vec>) { + // Descend through the types, looking for the various "base" + // components and collecting them into `out`. This is not written + // with `collect()` because of the need to sometimes skip subtrees + // in the `subtys` iterator (e.g., when encountering a + // projection). + match ty.sty { + ty::TyClosure(_, ref substs) => { + // FIXME(#27086). We do not accumulate from substs, since they + // don't represent reachable data. This means that, in + // practice, some of the lifetime parameters might not + // be in scope when the body runs, so long as there is + // no reachable data with that lifetime. For better or + // worse, this is consistent with fn types, however, + // which can also encapsulate data in this fashion + // (though it's somewhat harder, and typically + // requires virtual dispatch). + // + // Note that changing this (in a naive way, at least) + // causes regressions for what appears to be perfectly + // reasonable code like this: + // + // ``` + // fn foo<'a>(p: &Data<'a>) { + // bar(|q: &mut Parser| q.read_addr()) + // } + // fn bar(p: Box) { + // } + // ``` + // + // Note that `p` (and `'a`) are not used in the + // closure at all, but to meet the requirement that + // the closure type `C: 'static` (so it can be coerced + // to the object type), we get the requirement that + // `'a: 'static` since `'a` appears in the closure + // type `C`. + // + // A smarter fix might "prune" unused `func_substs` -- + // this would avoid breaking simple examples like + // this, but would still break others (which might + // indeed be invalid, depending on your POV). Pruning + // would be a subtle process, since we have to see + // what func/type parameters are used and unused, + // taking into consideration UFCS and so forth. - for &upvar_ty in substs.upvar_tys { - self.compute_components(upvar_ty, out); + for &upvar_ty in substs.upvar_tys { + self.compute_components(upvar_ty, out); + } } - } - // OutlivesTypeParameterEnv -- the actual checking that `X:'a` - // is implied by the environment is done in regionck. - ty::TyParam(p) => { - out.push(Component::Param(p)); - } - - // For projections, we prefer to generate an obligation like - // `>::Foo: 'a`, because this gives the - // regionck more ways to prove that it holds. However, - // regionck is not (at least currently) prepared to deal with - // higher-ranked regions that may appear in the - // trait-ref. Therefore, if we see any higher-ranke regions, - // we simply fallback to the most restrictive rule, which - // requires that `Pi: 'a` for all `i`. - ty::TyProjection(ref data) => { - if !data.has_escaping_regions() { - // best case: no escaping regions, so push the - // projection and skip the subtree (thus generating no - // constraints for Pi). This defers the choice between - // the rules OutlivesProjectionEnv, - // OutlivesProjectionTraitDef, and - // OutlivesProjectionComponents to regionck. - out.push(Component::Projection(*data)); - } else { - // fallback case: hard code - // OutlivesProjectionComponents. Continue walking - // through and constrain Pi. - let subcomponents = self.capture_components(ty); - out.push(Component::EscapingProjection(subcomponents)); + // OutlivesTypeParameterEnv -- the actual checking that `X:'a` + // is implied by the environment is done in regionck. + ty::TyParam(p) => { + out.push(Component::Param(p)); } - } - // If we encounter an inference variable, try to resolve it - // and proceed with resolved version. If we cannot resolve it, - // then record the unresolved variable as a component. - ty::TyInfer(_) => { - let ty = self.resolve_type_vars_if_possible(&ty); - if let ty::TyInfer(infer_ty) = ty.sty { - out.push(Component::UnresolvedInferenceVariable(infer_ty)); - } else { - self.compute_components(ty, out); + // For projections, we prefer to generate an obligation like + // `>::Foo: 'a`, because this gives the + // regionck more ways to prove that it holds. However, + // regionck is not (at least currently) prepared to deal with + // higher-ranked regions that may appear in the + // trait-ref. Therefore, if we see any higher-ranke regions, + // we simply fallback to the most restrictive rule, which + // requires that `Pi: 'a` for all `i`. + ty::TyProjection(ref data) => { + if !data.has_escaping_regions() { + // best case: no escaping regions, so push the + // projection and skip the subtree (thus generating no + // constraints for Pi). This defers the choice between + // the rules OutlivesProjectionEnv, + // OutlivesProjectionTraitDef, and + // OutlivesProjectionComponents to regionck. + out.push(Component::Projection(*data)); + } else { + // fallback case: hard code + // OutlivesProjectionComponents. Continue walking + // through and constrain Pi. + let subcomponents = self.capture_components(ty); + out.push(Component::EscapingProjection(subcomponents)); + } } - } - // Most types do not introduce any region binders, nor - // involve any other subtle cases, and so the WF relation - // simply constraints any regions referenced directly by - // the type and then visits the types that are lexically - // contained within. (The comments refer to relevant rules - // from RFC1214.) - ty::TyBool | // OutlivesScalar - ty::TyChar | // OutlivesScalar - ty::TyInt(..) | // OutlivesScalar - ty::TyUint(..) | // OutlivesScalar - ty::TyFloat(..) | // OutlivesScalar - ty::TyEnum(..) | // OutlivesNominalType - ty::TyStruct(..) | // OutlivesNominalType - ty::TyBox(..) | // OutlivesNominalType (ish) - ty::TyStr | // OutlivesScalar (ish) - ty::TyArray(..) | // ... - ty::TySlice(..) | // ... - ty::TyRawPtr(..) | // ... - ty::TyRef(..) | // OutlivesReference - ty::TyTuple(..) | // ... - ty::TyFnDef(..) | // OutlivesFunction (*) - ty::TyFnPtr(_) | // OutlivesFunction (*) - ty::TyTrait(..) | // OutlivesObject, OutlivesFragment (*) - ty::TyError => { - // (*) Bare functions and traits are both binders. In the - // RFC, this means we would add the bound regions to the - // "bound regions list". In our representation, no such - // list is maintained explicitly, because bound regions - // themselves can be readily identified. + // If we encounter an inference variable, try to resolve it + // and proceed with resolved version. If we cannot resolve it, + // then record the unresolved variable as a component. + ty::TyInfer(_) => { + let ty = self.resolve_type_vars_if_possible(&ty); + if let ty::TyInfer(infer_ty) = ty.sty { + out.push(Component::UnresolvedInferenceVariable(infer_ty)); + } else { + self.compute_components(ty, out); + } + } - push_region_constraints(out, ty.regions()); - for subty in ty.walk_shallow() { - self.compute_components(subty, out); + // Most types do not introduce any region binders, nor + // involve any other subtle cases, and so the WF relation + // simply constraints any regions referenced directly by + // the type and then visits the types that are lexically + // contained within. (The comments refer to relevant rules + // from RFC1214.) + ty::TyBool | // OutlivesScalar + ty::TyChar | // OutlivesScalar + ty::TyInt(..) | // OutlivesScalar + ty::TyUint(..) | // OutlivesScalar + ty::TyFloat(..) | // OutlivesScalar + ty::TyEnum(..) | // OutlivesNominalType + ty::TyStruct(..) | // OutlivesNominalType + ty::TyBox(..) | // OutlivesNominalType (ish) + ty::TyStr | // OutlivesScalar (ish) + ty::TyArray(..) | // ... + ty::TySlice(..) | // ... + ty::TyRawPtr(..) | // ... + ty::TyRef(..) | // OutlivesReference + ty::TyTuple(..) | // ... + ty::TyFnDef(..) | // OutlivesFunction (*) + ty::TyFnPtr(_) | // OutlivesFunction (*) + ty::TyTrait(..) | // OutlivesObject, OutlivesFragment (*) + ty::TyError => { + // (*) Bare functions and traits are both binders. In the + // RFC, this means we would add the bound regions to the + // "bound regions list". In our representation, no such + // list is maintained explicitly, because bound regions + // themselves can be readily identified. + + push_region_constraints(out, ty.regions()); + for subty in ty.walk_shallow() { + self.compute_components(subty, out); + } } } } -} -fn capture_components(&self, ty: Ty<'tcx>) -> Vec> { - let mut temp = vec![]; - push_region_constraints(&mut temp, ty.regions()); - for subty in ty.walk_shallow() { - self.compute_components(subty, &mut temp); + fn capture_components(&self, ty: Ty<'tcx>) -> Vec> { + let mut temp = vec![]; + push_region_constraints(&mut temp, ty.regions()); + for subty in ty.walk_shallow() { + self.compute_components(subty, &mut temp); + } + temp } - temp -} } fn push_region_constraints<'tcx>(out: &mut Vec>, regions: Vec) { diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index b6f1e86780b..725d40889ce 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -276,1806 +276,1815 @@ fn report_elision_failure( } impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { -pub fn opt_ast_region_to_region(&self, - rscope: &RegionScope, - default_span: Span, - opt_lifetime: &Option) -> ty::Region -{ - let r = match *opt_lifetime { - Some(ref lifetime) => { - ast_region_to_region(self.tcx(), lifetime) - } - - None => match rscope.anon_regions(default_span, 1) { - Ok(rs) => rs[0], - Err(params) => { - let mut err = struct_span_err!(self.tcx().sess, default_span, E0106, - "missing lifetime specifier"); - if let Some(params) = params { - report_elision_failure(&mut err, params); - } - err.emit(); - ty::ReStatic - } - } - }; - - debug!("opt_ast_region_to_region(opt_lifetime={:?}) yields {:?}", - opt_lifetime, - r); - - r -} - -/// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`, -/// returns an appropriate set of substitutions for this particular reference to `I`. -pub fn ast_path_substs_for_ty(&self, - rscope: &RegionScope, - span: Span, - param_mode: PathParamMode, - decl_generics: &ty::Generics<'tcx>, - item_segment: &hir::PathSegment) - -> Substs<'tcx> -{ - let tcx = self.tcx(); - - // ast_path_substs() is only called to convert paths that are - // known to refer to traits, types, or structs. In these cases, - // all type parameters defined for the item being referenced will - // be in the TypeSpace or SelfSpace. - // - // Note: in the case of traits, the self parameter is also - // defined, but we don't currently create a `type_param_def` for - // `Self` because it is implicit. - assert!(decl_generics.regions.all(|d| d.space == TypeSpace)); - assert!(decl_generics.types.all(|d| d.space != FnSpace)); - - let (regions, types, assoc_bindings) = match item_segment.parameters { - hir::AngleBracketedParameters(ref data) => { - self.convert_angle_bracketed_parameters(rscope, span, decl_generics, data) - } - hir::ParenthesizedParameters(..) => { - span_err!(tcx.sess, span, E0214, - "parenthesized parameters may only be used with a trait"); - let ty_param_defs = decl_generics.types.get_slice(TypeSpace); - (Substs::empty(), - ty_param_defs.iter().map(|_| tcx.types.err).collect(), - vec![]) - } - }; - - assoc_bindings.first().map(|b| self.tcx().prohibit_projection(b.span)); - - self.create_substs_for_ast_path(span, - param_mode, - decl_generics, - None, - types, - regions) -} - -fn create_region_substs(&self, - rscope: &RegionScope, - span: Span, - decl_generics: &ty::Generics<'tcx>, - regions_provided: Vec) - -> Substs<'tcx> -{ - let tcx = self.tcx(); - - // If the type is parameterized by this region, then replace this - // region with the current anon region binding (in other words, - // whatever & would get replaced with). - let expected_num_region_params = decl_generics.regions.len(TypeSpace); - let supplied_num_region_params = regions_provided.len(); - let regions = if expected_num_region_params == supplied_num_region_params { - regions_provided - } else { - let anon_regions = - rscope.anon_regions(span, expected_num_region_params); - - if supplied_num_region_params != 0 || anon_regions.is_err() { - report_lifetime_number_error(tcx, span, - supplied_num_region_params, - expected_num_region_params); - } - - match anon_regions { - Ok(anon_regions) => anon_regions, - Err(_) => (0..expected_num_region_params).map(|_| ty::ReStatic).collect() - } - }; - Substs::new_type(vec![], regions) -} - -/// Given the type/region arguments provided to some path (along with -/// an implicit Self, if this is a trait reference) returns the complete -/// set of substitutions. This may involve applying defaulted type parameters. -/// -/// Note that the type listing given here is *exactly* what the user provided. -/// -/// The `region_substs` should be the result of `create_region_substs` -/// -- that is, a substitution with no types but the correct number of -/// regions. -fn create_substs_for_ast_path(&self, - span: Span, - param_mode: PathParamMode, - decl_generics: &ty::Generics<'tcx>, - self_ty: Option>, - types_provided: Vec>, - region_substs: Substs<'tcx>) - -> Substs<'tcx> -{ - let tcx = self.tcx(); - - debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}, \ - types_provided={:?}, region_substs={:?})", - decl_generics, self_ty, types_provided, - region_substs); - - assert_eq!(region_substs.regions.len(TypeSpace), decl_generics.regions.len(TypeSpace)); - assert!(region_substs.types.is_empty()); - - // Convert the type parameters supplied by the user. - let ty_param_defs = decl_generics.types.get_slice(TypeSpace); - let formal_ty_param_count = ty_param_defs.len(); - let required_ty_param_count = ty_param_defs.iter() - .take_while(|x| x.default.is_none()) - .count(); - - let mut type_substs = self.get_type_substs_for_defs(span, - types_provided, - param_mode, - ty_param_defs, - region_substs.clone(), - self_ty); - - let supplied_ty_param_count = type_substs.len(); - check_type_argument_count(self.tcx(), span, supplied_ty_param_count, - required_ty_param_count, formal_ty_param_count); - - if supplied_ty_param_count < required_ty_param_count { - while type_substs.len() < required_ty_param_count { - type_substs.push(tcx.types.err); - } - } else if supplied_ty_param_count > formal_ty_param_count { - type_substs.truncate(formal_ty_param_count); - } - assert!(type_substs.len() >= required_ty_param_count && - type_substs.len() <= formal_ty_param_count); - - let mut substs = region_substs; - substs.types.extend(TypeSpace, type_substs.into_iter()); - - match self_ty { - None => { - // If no self-type is provided, it's still possible that - // one was declared, because this could be an object type. - } - Some(ty) => { - // If a self-type is provided, one should have been - // "declared" (in other words, this should be a - // trait-ref). - assert!(decl_generics.types.get_self().is_some()); - substs.types.push(SelfSpace, ty); - } - } - - let actual_supplied_ty_param_count = substs.types.len(TypeSpace); - for param in &ty_param_defs[actual_supplied_ty_param_count..] { - if let Some(default) = param.default { - // If we are converting an object type, then the - // `Self` parameter is unknown. However, some of the - // other type parameters may reference `Self` in their - // defaults. This will lead to an ICE if we are not - // careful! - if self_ty.is_none() && default.has_self_ty() { - span_err!(tcx.sess, span, E0393, - "the type parameter `{}` must be explicitly specified \ - in an object type because its default value `{}` references \ - the type `Self`", - param.name, - default); - substs.types.push(TypeSpace, tcx.types.err); - } else { - // This is a default type parameter. - let default = default.subst_spanned(tcx, - &substs, - Some(span)); - substs.types.push(TypeSpace, default); - } - } else { - span_bug!(span, "extra parameter without default"); - } - } - - debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}) -> {:?}", - decl_generics, self_ty, substs); - - substs -} - -/// Returns types_provided if it is not empty, otherwise populating the -/// type parameters with inference variables as appropriate. -fn get_type_substs_for_defs(&self, - span: Span, - types_provided: Vec>, - param_mode: PathParamMode, - ty_param_defs: &[ty::TypeParameterDef<'tcx>], - mut substs: Substs<'tcx>, - self_ty: Option>) - -> Vec> -{ - fn default_type_parameter<'tcx>(p: &ty::TypeParameterDef<'tcx>, self_ty: Option>) - -> Option> + pub fn opt_ast_region_to_region(&self, + rscope: &RegionScope, + default_span: Span, + opt_lifetime: &Option) -> ty::Region { - if let Some(ref default) = p.default { - if self_ty.is_none() && default.has_self_ty() { - // There is no suitable inference default for a type parameter - // that references self with no self-type provided. - return None; - } - } - - Some(p.clone()) - } - - if param_mode == PathParamMode::Optional && types_provided.is_empty() { - ty_param_defs - .iter() - .map(|p| self.ty_infer(default_type_parameter(p, self_ty), Some(&mut substs), - Some(TypeSpace), span)) - .collect() - } else { - types_provided - } -} - -fn convert_angle_bracketed_parameters(&self, - rscope: &RegionScope, - span: Span, - decl_generics: &ty::Generics<'tcx>, - data: &hir::AngleBracketedParameterData) - -> (Substs<'tcx>, - Vec>, - Vec>) -{ - let regions: Vec<_> = - data.lifetimes.iter() - .map(|l| ast_region_to_region(self.tcx(), l)) - .collect(); - - let region_substs = - self.create_region_substs(rscope, span, decl_generics, regions); - - let types: Vec<_> = - data.types.iter() - .enumerate() - .map(|(i,t)| self.ast_ty_arg_to_ty(rscope, decl_generics, - i, ®ion_substs, t)) - .collect(); - - let assoc_bindings: Vec<_> = - data.bindings.iter() - .map(|b| ConvertedBinding { item_name: b.name, - ty: self.ast_ty_to_ty(rscope, &b.ty), - span: b.span }) - .collect(); - - (region_substs, types, assoc_bindings) -} - -/// Returns the appropriate lifetime to use for any output lifetimes -/// (if one exists) and a vector of the (pattern, number of lifetimes) -/// corresponding to each input type/pattern. -fn find_implied_output_region(&self, - input_tys: &[Ty<'tcx>], - input_pats: Vec) -> ElidedLifetime -{ - let tcx = self.tcx(); - let mut lifetimes_for_params = Vec::new(); - let mut possible_implied_output_region = None; - - for (input_type, input_pat) in input_tys.iter().zip(input_pats) { - let mut regions = FnvHashSet(); - let have_bound_regions = tcx.collect_regions(input_type, &mut regions); - - debug!("find_implied_output_regions: collected {:?} from {:?} \ - have_bound_regions={:?}", ®ions, input_type, have_bound_regions); - - if regions.len() == 1 { - // there's a chance that the unique lifetime of this - // iteration will be the appropriate lifetime for output - // parameters, so lets store it. - possible_implied_output_region = regions.iter().cloned().next(); - } - - lifetimes_for_params.push(ElisionFailureInfo { - name: input_pat, - lifetime_count: regions.len(), - have_bound_regions: have_bound_regions - }); - } - - if lifetimes_for_params.iter().map(|e| e.lifetime_count).sum::() == 1 { - Ok(possible_implied_output_region.unwrap()) - } else { - Err(Some(lifetimes_for_params)) - } -} - -fn convert_ty_with_lifetime_elision(&self, - elided_lifetime: ElidedLifetime, - ty: &hir::Ty) - -> Ty<'tcx> -{ - match elided_lifetime { - Ok(implied_output_region) => { - let rb = ElidableRscope::new(implied_output_region); - self.ast_ty_to_ty(&rb, ty) - } - Err(param_lifetimes) => { - // All regions must be explicitly specified in the output - // if the lifetime elision rules do not apply. This saves - // the user from potentially-confusing errors. - let rb = UnelidableRscope::new(param_lifetimes); - self.ast_ty_to_ty(&rb, ty) - } - } -} - -fn convert_parenthesized_parameters(&self, - rscope: &RegionScope, - span: Span, - decl_generics: &ty::Generics<'tcx>, - data: &hir::ParenthesizedParameterData) - -> (Substs<'tcx>, - Vec>, - Vec>) -{ - let region_substs = - self.create_region_substs(rscope, span, decl_generics, Vec::new()); - - let binding_rscope = BindingRscope::new(); - let inputs = - data.inputs.iter() - .map(|a_t| self.ast_ty_arg_to_ty(&binding_rscope, decl_generics, - 0, ®ion_substs, a_t)) - .collect::>>(); - - let input_params = vec![String::new(); inputs.len()]; - let implied_output_region = self.find_implied_output_region(&inputs, input_params); - - let input_ty = self.tcx().mk_tup(inputs); - - let (output, output_span) = match data.output { - Some(ref output_ty) => { - (self.convert_ty_with_lifetime_elision(implied_output_region, &output_ty), - output_ty.span) - } - None => { - (self.tcx().mk_nil(), data.span) - } - }; - - let output_binding = ConvertedBinding { - item_name: token::intern(FN_OUTPUT_NAME), - ty: output, - span: output_span - }; - - (region_substs, vec![input_ty], vec![output_binding]) -} - -pub fn instantiate_poly_trait_ref(&self, - rscope: &RegionScope, - ast_trait_ref: &hir::PolyTraitRef, - self_ty: Option>, - poly_projections: &mut Vec>) - -> ty::PolyTraitRef<'tcx> -{ - let trait_ref = &ast_trait_ref.trait_ref; - let trait_def_id = self.trait_def_id(trait_ref); - self.ast_path_to_poly_trait_ref(rscope, - trait_ref.path.span, - PathParamMode::Explicit, - trait_def_id, - self_ty, - trait_ref.path.segments.last().unwrap(), - poly_projections) -} - -/// Instantiates the path for the given trait reference, assuming that it's -/// bound to a valid trait type. Returns the def_id for the defining trait. -/// Fails if the type is a type other than a trait type. -/// -/// If the `projections` argument is `None`, then assoc type bindings like `Foo` -/// are disallowed. Otherwise, they are pushed onto the vector given. -pub fn instantiate_mono_trait_ref(&self, - rscope: &RegionScope, - trait_ref: &hir::TraitRef, - self_ty: Option>) - -> ty::TraitRef<'tcx> -{ - let trait_def_id = self.trait_def_id(trait_ref); - self.ast_path_to_mono_trait_ref(rscope, - trait_ref.path.span, - PathParamMode::Explicit, - trait_def_id, - self_ty, - trait_ref.path.segments.last().unwrap()) -} - -fn trait_def_id(&self, trait_ref: &hir::TraitRef) -> DefId { - let path = &trait_ref.path; - match ::lookup_full_def(self.tcx(), path.span, trait_ref.ref_id) { - Def::Trait(trait_def_id) => trait_def_id, - Def::Err => { - self.tcx().sess.fatal("cannot continue compilation due to previous error"); - } - _ => { - span_fatal!(self.tcx().sess, path.span, E0245, "`{}` is not a trait", - path); - } - } -} - -fn object_path_to_poly_trait_ref(&self, - rscope: &RegionScope, - span: Span, - param_mode: PathParamMode, - trait_def_id: DefId, - trait_segment: &hir::PathSegment, - mut projections: &mut Vec>) - -> ty::PolyTraitRef<'tcx> -{ - self.ast_path_to_poly_trait_ref(rscope, - span, - param_mode, - trait_def_id, - None, - trait_segment, - projections) -} - -fn ast_path_to_poly_trait_ref(&self, - rscope: &RegionScope, - span: Span, - param_mode: PathParamMode, - trait_def_id: DefId, - self_ty: Option>, - trait_segment: &hir::PathSegment, - poly_projections: &mut Vec>) - -> ty::PolyTraitRef<'tcx> -{ - debug!("ast_path_to_poly_trait_ref(trait_segment={:?})", trait_segment); - // The trait reference introduces a binding level here, so - // we need to shift the `rscope`. It'd be nice if we could - // do away with this rscope stuff and work this knowledge - // into resolve_lifetimes, as we do with non-omitted - // lifetimes. Oh well, not there yet. - let shifted_rscope = &ShiftedRscope::new(rscope); - - let (substs, assoc_bindings) = - self.create_substs_for_ast_trait_ref(shifted_rscope, - span, - param_mode, - trait_def_id, - self_ty, - trait_segment); - let poly_trait_ref = ty::Binder(ty::TraitRef::new(trait_def_id, substs)); - - { - let converted_bindings = - assoc_bindings - .iter() - .filter_map(|binding| { - // specify type to assert that error was already reported in Err case: - let predicate: Result<_, ErrorReported> = - self.ast_type_binding_to_poly_projection_predicate(poly_trait_ref.clone(), - self_ty, - binding); - predicate.ok() // ok to ignore Err() because ErrorReported (see above) - }); - poly_projections.extend(converted_bindings); - } - - debug!("ast_path_to_poly_trait_ref(trait_segment={:?}, projections={:?}) -> {:?}", - trait_segment, poly_projections, poly_trait_ref); - poly_trait_ref -} - -fn ast_path_to_mono_trait_ref(&self, - rscope: &RegionScope, - span: Span, - param_mode: PathParamMode, - trait_def_id: DefId, - self_ty: Option>, - trait_segment: &hir::PathSegment) - -> ty::TraitRef<'tcx> -{ - let (substs, assoc_bindings) = - self.create_substs_for_ast_trait_ref(rscope, - span, - param_mode, - trait_def_id, - self_ty, - trait_segment); - assoc_bindings.first().map(|b| self.tcx().prohibit_projection(b.span)); - ty::TraitRef::new(trait_def_id, substs) -} - -fn create_substs_for_ast_trait_ref(&self, - rscope: &RegionScope, - span: Span, - param_mode: PathParamMode, - trait_def_id: DefId, - self_ty: Option>, - trait_segment: &hir::PathSegment) - -> (&'tcx Substs<'tcx>, Vec>) -{ - debug!("create_substs_for_ast_trait_ref(trait_segment={:?})", - trait_segment); - - let trait_def = match self.get_trait_def(span, trait_def_id) { - Ok(trait_def) => trait_def, - Err(ErrorReported) => { - // No convenient way to recover from a cycle here. Just bail. Sorry! - self.tcx().sess.abort_if_errors(); - bug!("ErrorReported returned, but no errors reports?") - } - }; - - let (regions, types, assoc_bindings) = match trait_segment.parameters { - hir::AngleBracketedParameters(ref data) => { - // For now, require that parenthetical notation be used - // only with `Fn()` etc. - if !self.tcx().sess.features.borrow().unboxed_closures && trait_def.paren_sugar { - emit_feature_err(&self.tcx().sess.parse_sess.span_diagnostic, - "unboxed_closures", span, GateIssue::Language, - "\ - the precise format of `Fn`-family traits' type parameters is \ - subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead"); + let r = match *opt_lifetime { + Some(ref lifetime) => { + ast_region_to_region(self.tcx(), lifetime) } - self.convert_angle_bracketed_parameters(rscope, span, &trait_def.generics, data) - } - hir::ParenthesizedParameters(ref data) => { - // For now, require that parenthetical notation be used - // only with `Fn()` etc. - if !self.tcx().sess.features.borrow().unboxed_closures && !trait_def.paren_sugar { - emit_feature_err(&self.tcx().sess.parse_sess.span_diagnostic, - "unboxed_closures", span, GateIssue::Language, - "\ - parenthetical notation is only stable when used with `Fn`-family traits"); - } - - self.convert_parenthesized_parameters(rscope, span, &trait_def.generics, data) - } - }; - - let substs = self.create_substs_for_ast_path(span, - param_mode, - &trait_def.generics, - self_ty, - types, - regions); - - (self.tcx().mk_substs(substs), assoc_bindings) -} - -fn ast_type_binding_to_poly_projection_predicate(&self, - mut trait_ref: ty::PolyTraitRef<'tcx>, - self_ty: Option>, - binding: &ConvertedBinding<'tcx>) - -> Result, ErrorReported> -{ - let tcx = self.tcx(); - - // Given something like `U : SomeTrait`, we want to produce a - // predicate like `::T = X`. This is somewhat - // subtle in the event that `T` is defined in a supertrait of - // `SomeTrait`, because in that case we need to upcast. - // - // That is, consider this case: - // - // ``` - // trait SubTrait : SuperTrait { } - // trait SuperTrait { type T; } - // - // ... B : SubTrait ... - // ``` - // - // We want to produce `>::T == foo`. - - // Simple case: X is defined in the current trait. - if self.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) { - return Ok(ty::Binder(ty::ProjectionPredicate { // <-------------------+ - projection_ty: ty::ProjectionTy { // | - trait_ref: trait_ref.skip_binder().clone(), // Binder moved here --+ - item_name: binding.item_name, - }, - ty: binding.ty, - })); - } - - // Otherwise, we have to walk through the supertraits to find - // those that do. This is complicated by the fact that, for an - // object type, the `Self` type is not present in the - // substitutions (after all, it's being constructed right now), - // but the `supertraits` iterator really wants one. To handle - // this, we currently insert a dummy type and then remove it - // later. Yuck. - - let dummy_self_ty = tcx.mk_infer(ty::FreshTy(0)); - if self_ty.is_none() { // if converting for an object type - let mut dummy_substs = trait_ref.skip_binder().substs.clone(); // binder moved here -+ - assert!(dummy_substs.self_ty().is_none()); // | - dummy_substs.types.push(SelfSpace, dummy_self_ty); // | - trait_ref = ty::Binder(ty::TraitRef::new(trait_ref.def_id(), // <------------+ - tcx.mk_substs(dummy_substs))); - } - - self.ensure_super_predicates(binding.span, trait_ref.def_id())?; - - let mut candidates: Vec = - traits::supertraits(tcx, trait_ref.clone()) - .filter(|r| self.trait_defines_associated_type_named(r.def_id(), binding.item_name)) - .collect(); - - // If converting for an object type, then remove the dummy-ty from `Self` now. - // Yuckety yuck. - if self_ty.is_none() { - for candidate in &mut candidates { - let mut dummy_substs = candidate.0.substs.clone(); - assert!(dummy_substs.self_ty() == Some(dummy_self_ty)); - dummy_substs.types.pop(SelfSpace); - *candidate = ty::Binder(ty::TraitRef::new(candidate.def_id(), - tcx.mk_substs(dummy_substs))); - } - } - - let candidate = self.one_bound_for_assoc_type(candidates, - &trait_ref.to_string(), - &binding.item_name.as_str(), - binding.span)?; - - Ok(ty::Binder(ty::ProjectionPredicate { // <-------------------------+ - projection_ty: ty::ProjectionTy { // | - trait_ref: candidate.skip_binder().clone(), // binder is moved up here --+ - item_name: binding.item_name, - }, - ty: binding.ty, - })) -} - -fn ast_path_to_ty(&self, - rscope: &RegionScope, - span: Span, - param_mode: PathParamMode, - did: DefId, - item_segment: &hir::PathSegment) - -> Ty<'tcx> -{ - let tcx = self.tcx(); - let (generics, decl_ty) = match self.get_item_type_scheme(span, did) { - Ok(ty::TypeScheme { generics, ty: decl_ty }) => { - (generics, decl_ty) - } - Err(ErrorReported) => { - return tcx.types.err; - } - }; - - let substs = self.ast_path_substs_for_ty(rscope, - span, - param_mode, - &generics, - item_segment); - - // FIXME(#12938): This is a hack until we have full support for DST. - if Some(did) == self.tcx().lang_items.owned_box() { - assert_eq!(substs.types.len(TypeSpace), 1); - return self.tcx().mk_box(*substs.types.get(TypeSpace, 0)); - } - - decl_ty.subst(self.tcx(), &substs) -} - -fn ast_ty_to_trait_ref(&self, - rscope: &RegionScope, - ty: &hir::Ty, - bounds: &[hir::TyParamBound]) - -> Result, ErrorReported> -{ - /*! - * In a type like `Foo + Send`, we want to wait to collect the - * full set of bounds before we make the object type, because we - * need them to infer a region bound. (For example, if we tried - * made a type from just `Foo`, then it wouldn't be enough to - * infer a 'static bound, and hence the user would get an error.) - * So this function is used when we're dealing with a sum type to - * convert the LHS. It only accepts a type that refers to a trait - * name, and reports an error otherwise. - */ - - match ty.node { - hir::TyPath(None, ref path) => { - let def = match self.tcx().def_map.borrow().get(&ty.id) { - Some(&def::PathResolution { base_def, depth: 0, .. }) => Some(base_def), - _ => None - }; - match def { - Some(Def::Trait(trait_def_id)) => { - let mut projection_bounds = Vec::new(); - let trait_ref = - self.object_path_to_poly_trait_ref(rscope, - path.span, - PathParamMode::Explicit, - trait_def_id, - path.segments.last().unwrap(), - &mut projection_bounds); - Ok((trait_ref, projection_bounds)) - } - _ => { - span_err!(self.tcx().sess, ty.span, E0172, "expected a reference to a trait"); - Err(ErrorReported) - } - } - } - _ => { - let mut err = struct_span_err!(self.tcx().sess, ty.span, E0178, - "expected a path on the left-hand side of `+`, not `{}`", - pprust::ty_to_string(ty)); - let hi = bounds.iter().map(|x| match *x { - hir::TraitTyParamBound(ref tr, _) => tr.span.hi, - hir::RegionTyParamBound(ref r) => r.span.hi, - }).max_by_key(|x| x.to_usize()); - let full_span = hi.map(|hi| Span { - lo: ty.span.lo, - hi: hi, - expn_id: ty.span.expn_id, - }); - match (&ty.node, full_span) { - (&hir::TyRptr(None, ref mut_ty), Some(full_span)) => { - let mutbl_str = if mut_ty.mutbl == hir::MutMutable { "mut " } else { "" }; - err.span_suggestion(full_span, "try adding parentheses (per RFC 438):", - format!("&{}({} +{})", - mutbl_str, - pprust::ty_to_string(&mut_ty.ty), - pprust::bounds_to_string(bounds))); - } - (&hir::TyRptr(Some(ref lt), ref mut_ty), Some(full_span)) => { - let mutbl_str = if mut_ty.mutbl == hir::MutMutable { "mut " } else { "" }; - err.span_suggestion(full_span, "try adding parentheses (per RFC 438):", - format!("&{} {}({} +{})", - pprust::lifetime_to_string(lt), - mutbl_str, - pprust::ty_to_string(&mut_ty.ty), - pprust::bounds_to_string(bounds))); - } - - _ => { - help!(&mut err, - "perhaps you forgot parentheses? (per RFC 438)"); - } - } - err.emit(); - Err(ErrorReported) - } - } -} - -fn trait_ref_to_object_type(&self, - rscope: &RegionScope, - span: Span, - trait_ref: ty::PolyTraitRef<'tcx>, - projection_bounds: Vec>, - bounds: &[hir::TyParamBound]) - -> Ty<'tcx> -{ - let existential_bounds = self.conv_existential_bounds(rscope, - span, - trait_ref.clone(), - projection_bounds, - bounds); - - let result = self.make_object_type(span, trait_ref, existential_bounds); - debug!("trait_ref_to_object_type: result={:?}", - result); - - result -} - -fn make_object_type(&self, - span: Span, - principal: ty::PolyTraitRef<'tcx>, - bounds: ty::ExistentialBounds<'tcx>) - -> Ty<'tcx> { - let tcx = self.tcx(); - let object = ty::TraitTy { - principal: principal, - bounds: bounds - }; - let object_trait_ref = - object.principal_trait_ref_with_self_ty(tcx, tcx.types.err); - - // ensure the super predicates and stop if we encountered an error - if self.ensure_super_predicates(span, principal.def_id()).is_err() { - return tcx.types.err; - } - - // check that there are no gross object safety violations, - // most importantly, that the supertraits don't contain Self, - // to avoid ICE-s. - let object_safety_violations = - tcx.astconv_object_safety_violations(principal.def_id()); - if !object_safety_violations.is_empty() { - tcx.report_object_safety_error( - span, principal.def_id(), None, object_safety_violations) - .unwrap().emit(); - return tcx.types.err; - } - - let mut associated_types: FnvHashSet<(DefId, ast::Name)> = - traits::supertraits(tcx, object_trait_ref) - .flat_map(|tr| { - let trait_def = tcx.lookup_trait_def(tr.def_id()); - trait_def.associated_type_names - .clone() - .into_iter() - .map(move |associated_type_name| (tr.def_id(), associated_type_name)) - }) - .collect(); - - for projection_bound in &object.bounds.projection_bounds { - let pair = (projection_bound.0.projection_ty.trait_ref.def_id, - projection_bound.0.projection_ty.item_name); - associated_types.remove(&pair); - } - - for (trait_def_id, name) in associated_types { - span_err!(tcx.sess, span, E0191, - "the value of the associated type `{}` (from the trait `{}`) must be specified", - name, - tcx.item_path_str(trait_def_id)); - } - - tcx.mk_trait(object.principal, object.bounds) -} - -fn report_ambiguous_associated_type(&self, - span: Span, - type_str: &str, - trait_str: &str, - name: &str) { - span_err!(self.tcx().sess, span, E0223, - "ambiguous associated type; specify the type using the syntax \ - `<{} as {}>::{}`", - type_str, trait_str, name); -} - -// Search for a bound on a type parameter which includes the associated item -// given by assoc_name. ty_param_node_id is the node id for the type parameter -// (which might be `Self`, but only if it is the `Self` of a trait, not an -// impl). This function will fail if there are no suitable bounds or there is -// any ambiguity. -fn find_bound_for_assoc_item(&self, - ty_param_node_id: ast::NodeId, - ty_param_name: ast::Name, - assoc_name: ast::Name, - span: Span) - -> Result, ErrorReported> -{ - let tcx = self.tcx(); - - let bounds = match self.get_type_parameter_bounds(span, ty_param_node_id) { - Ok(v) => v, - Err(ErrorReported) => { - return Err(ErrorReported); - } - }; - - // Ensure the super predicates and stop if we encountered an error. - if bounds.iter().any(|b| self.ensure_super_predicates(span, b.def_id()).is_err()) { - return Err(ErrorReported); - } - - // Check that there is exactly one way to find an associated type with the - // correct name. - let suitable_bounds: Vec<_> = - traits::transitive_bounds(tcx, &bounds) - .filter(|b| self.trait_defines_associated_type_named(b.def_id(), assoc_name)) - .collect(); - - self.one_bound_for_assoc_type(suitable_bounds, - &ty_param_name.as_str(), - &assoc_name.as_str(), - span) -} - - -// Checks that bounds contains exactly one element and reports appropriate -// errors otherwise. -fn one_bound_for_assoc_type(&self, - bounds: Vec>, - ty_param_name: &str, - assoc_name: &str, - span: Span) - -> Result, ErrorReported> -{ - if bounds.is_empty() { - span_err!(self.tcx().sess, span, E0220, - "associated type `{}` not found for `{}`", - assoc_name, - ty_param_name); - return Err(ErrorReported); - } - - if bounds.len() > 1 { - let mut err = struct_span_err!(self.tcx().sess, span, E0221, - "ambiguous associated type `{}` in bounds of `{}`", - assoc_name, - ty_param_name); - - for bound in &bounds { - span_note!(&mut err, span, - "associated type `{}` could derive from `{}`", - ty_param_name, - bound); - } - err.emit(); - } - - Ok(bounds[0].clone()) -} - -// Create a type from a path to an associated type. -// For a path A::B::C::D, ty and ty_path_def are the type and def for A::B::C -// and item_segment is the path segment for D. We return a type and a def for -// the whole path. -// Will fail except for T::A and Self::A; i.e., if ty/ty_path_def are not a type -// parameter or Self. -fn associated_path_def_to_ty(&self, - span: Span, - ty: Ty<'tcx>, - ty_path_def: Def, - item_segment: &hir::PathSegment) - -> (Ty<'tcx>, Def) -{ - let tcx = self.tcx(); - let assoc_name = item_segment.identifier.name; - - debug!("associated_path_def_to_ty: {:?}::{}", ty, assoc_name); - - tcx.prohibit_type_params(slice::ref_slice(item_segment)); - - // Find the type of the associated item, and the trait where the associated - // item is declared. - let bound = match (&ty.sty, ty_path_def) { - (_, Def::SelfTy(Some(trait_did), Some(impl_id))) => { - // `Self` in an impl of a trait - we have a concrete self type and a - // trait reference. - let trait_ref = tcx.impl_trait_ref(tcx.map.local_def_id(impl_id)).unwrap(); - let trait_ref = if let Some(free_substs) = self.get_free_substs() { - trait_ref.subst(tcx, free_substs) - } else { - trait_ref - }; - - if self.ensure_super_predicates(span, trait_did).is_err() { - return (tcx.types.err, ty_path_def); - } - - let candidates: Vec = - traits::supertraits(tcx, ty::Binder(trait_ref)) - .filter(|r| self.trait_defines_associated_type_named(r.def_id(), - assoc_name)) - .collect(); - - match self.one_bound_for_assoc_type(candidates, - "Self", - &assoc_name.as_str(), - span) { - Ok(bound) => bound, - Err(ErrorReported) => return (tcx.types.err, ty_path_def), - } - } - (&ty::TyParam(_), Def::SelfTy(Some(trait_did), None)) => { - let trait_node_id = tcx.map.as_local_node_id(trait_did).unwrap(); - match self.find_bound_for_assoc_item(trait_node_id, - keywords::SelfType.name(), - assoc_name, - span) { - Ok(bound) => bound, - Err(ErrorReported) => return (tcx.types.err, ty_path_def), - } - } - (&ty::TyParam(_), Def::TyParam(_, _, param_did, param_name)) => { - let param_node_id = tcx.map.as_local_node_id(param_did).unwrap(); - match self.find_bound_for_assoc_item(param_node_id, - param_name, - assoc_name, - span) { - Ok(bound) => bound, - Err(ErrorReported) => return (tcx.types.err, ty_path_def), - } - } - _ => { - self.report_ambiguous_associated_type(span, - &ty.to_string(), - "Trait", - &assoc_name.as_str()); - return (tcx.types.err, ty_path_def); - } - }; - - let trait_did = bound.0.def_id; - let ty = self.projected_ty_from_poly_trait_ref(span, bound, assoc_name); - - let item_did = if let Some(trait_id) = tcx.map.as_local_node_id(trait_did) { - // `ty::trait_items` used below requires information generated - // by type collection, which may be in progress at this point. - match tcx.map.expect_item(trait_id).node { - hir::ItemTrait(_, _, _, ref trait_items) => { - let item = trait_items.iter() - .find(|i| i.name == assoc_name) - .expect("missing associated type"); - tcx.map.local_def_id(item.id) - } - _ => bug!() - } - } else { - let trait_items = tcx.trait_items(trait_did); - let item = trait_items.iter().find(|i| i.name() == assoc_name); - item.expect("missing associated type").def_id() - }; - - (ty, Def::AssociatedTy(trait_did, item_did)) -} - -fn qpath_to_ty(&self, - rscope: &RegionScope, - span: Span, - param_mode: PathParamMode, - opt_self_ty: Option>, - trait_def_id: DefId, - trait_segment: &hir::PathSegment, - item_segment: &hir::PathSegment) - -> Ty<'tcx> -{ - let tcx = self.tcx(); - - tcx.prohibit_type_params(slice::ref_slice(item_segment)); - - let self_ty = if let Some(ty) = opt_self_ty { - ty - } else { - let path_str = tcx.item_path_str(trait_def_id); - self.report_ambiguous_associated_type(span, - "Type", - &path_str, - &item_segment.identifier.name.as_str()); - return tcx.types.err; - }; - - debug!("qpath_to_ty: self_type={:?}", self_ty); - - let trait_ref = self.ast_path_to_mono_trait_ref(rscope, - span, - param_mode, - trait_def_id, - Some(self_ty), - trait_segment); - - debug!("qpath_to_ty: trait_ref={:?}", trait_ref); - - self.projected_ty(span, trait_ref, item_segment.identifier.name) -} - -/// Convert a type supplied as value for a type argument from AST into our -/// our internal representation. This is the same as `ast_ty_to_ty` but that -/// it applies the object lifetime default. -/// -/// # Parameters -/// -/// * `this`, `rscope`: the surrounding context -/// * `decl_generics`: the generics of the struct/enum/trait declaration being -/// referenced -/// * `index`: the index of the type parameter being instantiated from the list -/// (we assume it is in the `TypeSpace`) -/// * `region_substs`: a partial substitution consisting of -/// only the region type parameters being supplied to this type. -/// * `ast_ty`: the ast representation of the type being supplied -pub fn ast_ty_arg_to_ty(&self, - rscope: &RegionScope, - decl_generics: &ty::Generics<'tcx>, - index: usize, - region_substs: &Substs<'tcx>, - ast_ty: &hir::Ty) - -> Ty<'tcx> -{ - let tcx = self.tcx(); - - if let Some(def) = decl_generics.types.opt_get(TypeSpace, index) { - let object_lifetime_default = def.object_lifetime_default.subst(tcx, region_substs); - let rscope1 = &ObjectLifetimeDefaultRscope::new(rscope, object_lifetime_default); - self.ast_ty_to_ty(rscope1, ast_ty) - } else { - self.ast_ty_to_ty(rscope, ast_ty) - } -} - -// Check the base def in a PathResolution and convert it to a Ty. If there are -// associated types in the PathResolution, these will need to be separately -// resolved. -fn base_def_to_ty(&self, - rscope: &RegionScope, - span: Span, - param_mode: PathParamMode, - def: &Def, - opt_self_ty: Option>, - base_segments: &[hir::PathSegment]) - -> Ty<'tcx> { - let tcx = self.tcx(); - - match *def { - Def::Trait(trait_def_id) => { - // N.B. this case overlaps somewhat with - // TyObjectSum, see that fn for details - let mut projection_bounds = Vec::new(); - - let trait_ref = - self.object_path_to_poly_trait_ref(rscope, - span, - param_mode, - trait_def_id, - base_segments.last().unwrap(), - &mut projection_bounds); - - tcx.prohibit_type_params(base_segments.split_last().unwrap().1); - self.trait_ref_to_object_type(rscope, - span, - trait_ref, - projection_bounds, - &[]) - } - Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) => { - tcx.prohibit_type_params(base_segments.split_last().unwrap().1); - self.ast_path_to_ty(rscope, - span, - param_mode, - did, - base_segments.last().unwrap()) - } - Def::TyParam(space, index, _, name) => { - tcx.prohibit_type_params(base_segments); - tcx.mk_param(space, index, name) - } - Def::SelfTy(_, Some(impl_id)) => { - // Self in impl (we know the concrete type). - tcx.prohibit_type_params(base_segments); - let ty = tcx.node_id_to_type(impl_id); - if let Some(free_substs) = self.get_free_substs() { - ty.subst(tcx, free_substs) - } else { - ty - } - } - Def::SelfTy(Some(_), None) => { - // Self in trait. - tcx.prohibit_type_params(base_segments); - tcx.mk_self_type() - } - Def::AssociatedTy(trait_did, _) => { - tcx.prohibit_type_params(&base_segments[..base_segments.len()-2]); - self.qpath_to_ty(rscope, - span, - param_mode, - opt_self_ty, - trait_did, - &base_segments[base_segments.len()-2], - base_segments.last().unwrap()) - } - Def::Mod(..) => { - // Used as sentinel by callers to indicate the `::A::B::C` form. - // FIXME(#22519) This part of the resolution logic should be - // avoided entirely for that form, once we stop needed a Def - // for `associated_path_def_to_ty`. - // Fixing this will also let use resolve ::Foo the same way we - // resolve Self::Foo, at the moment we can't resolve the former because - // we don't have the trait information around, which is just sad. - - assert!(base_segments.is_empty()); - - opt_self_ty.expect("missing T in ::a::b::c") - } - Def::PrimTy(prim_ty) => { - tcx.prim_ty_to_ty(base_segments, prim_ty) - } - Def::Err => { - self.set_tainted_by_errors(); - return self.tcx().types.err; - } - _ => { - span_err!(tcx.sess, span, E0248, - "found value `{}` used as a type", - tcx.item_path_str(def.def_id())); - return self.tcx().types.err; - } - } -} - -// Note that both base_segments and assoc_segments may be empty, although not at -// the same time. -pub fn finish_resolving_def_to_ty(&self, - rscope: &RegionScope, - span: Span, - param_mode: PathParamMode, - def: &Def, - opt_self_ty: Option>, - base_segments: &[hir::PathSegment], - assoc_segments: &[hir::PathSegment]) - -> Ty<'tcx> { - let mut ty = self.base_def_to_ty(rscope, - span, - param_mode, - def, - opt_self_ty, - base_segments); - let mut def = *def; - // If any associated type segments remain, attempt to resolve them. - for segment in assoc_segments { - if ty.sty == ty::TyError { - break; - } - // This is pretty bad (it will fail except for T::A and Self::A). - let (a_ty, a_def) = self.associated_path_def_to_ty(span, - ty, - def, - segment); - ty = a_ty; - def = a_def; - } - ty -} - -/// Parses the programmer's textual representation of a type into our -/// internal notion of a type. -pub fn ast_ty_to_ty(&self, rscope: &RegionScope, ast_ty: &hir::Ty) -> Ty<'tcx> { - debug!("ast_ty_to_ty(id={:?}, ast_ty={:?})", - ast_ty.id, ast_ty); - - let tcx = self.tcx(); - - match ast_ty.node { - hir::TyVec(ref ty) => { - tcx.mk_slice(self.ast_ty_to_ty(rscope, &ty)) - } - hir::TyObjectSum(ref ty, ref bounds) => { - match self.ast_ty_to_trait_ref(rscope, &ty, bounds) { - Ok((trait_ref, projection_bounds)) => { - self.trait_ref_to_object_type(rscope, - ast_ty.span, - trait_ref, - projection_bounds, - bounds) - } - Err(ErrorReported) => { - self.tcx().types.err - } - } - } - hir::TyPtr(ref mt) => { - tcx.mk_ptr(ty::TypeAndMut { - ty: self.ast_ty_to_ty(rscope, &mt.ty), - mutbl: mt.mutbl - }) - } - hir::TyRptr(ref region, ref mt) => { - let r = self.opt_ast_region_to_region(rscope, ast_ty.span, region); - debug!("TyRef r={:?}", r); - let rscope1 = - &ObjectLifetimeDefaultRscope::new( - rscope, - ty::ObjectLifetimeDefault::Specific(r)); - let t = self.ast_ty_to_ty(rscope1, &mt.ty); - tcx.mk_ref(tcx.mk_region(r), ty::TypeAndMut {ty: t, mutbl: mt.mutbl}) - } - hir::TyTup(ref fields) => { - let flds = fields.iter() - .map(|t| self.ast_ty_to_ty(rscope, &t)) - .collect(); - tcx.mk_tup(flds) - } - hir::TyBareFn(ref bf) => { - require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span); - tcx.mk_fn_ptr(self.ty_of_bare_fn(bf.unsafety, bf.abi, &bf.decl)) - } - hir::TyPolyTraitRef(ref bounds) => { - self.conv_ty_poly_trait_ref(rscope, ast_ty.span, bounds) - } - hir::TyPath(ref maybe_qself, ref path) => { - let path_res = if let Some(&d) = tcx.def_map.borrow().get(&ast_ty.id) { - d - } else if let Some(hir::QSelf { position: 0, .. }) = *maybe_qself { - // Create some fake resolution that can't possibly be a type. - def::PathResolution { - base_def: Def::Mod(tcx.map.local_def_id(ast::CRATE_NODE_ID)), - depth: path.segments.len() - } - } else { - span_bug!(ast_ty.span, "unbound path {:?}", ast_ty) - }; - let def = path_res.base_def; - let base_ty_end = path.segments.len() - path_res.depth; - let opt_self_ty = maybe_qself.as_ref().map(|qself| { - self.ast_ty_to_ty(rscope, &qself.ty) - }); - let ty = self.finish_resolving_def_to_ty(rscope, - ast_ty.span, - PathParamMode::Explicit, - &def, - opt_self_ty, - &path.segments[..base_ty_end], - &path.segments[base_ty_end..]); - - if path_res.depth != 0 && ty.sty != ty::TyError { - // Write back the new resolution. - tcx.def_map.borrow_mut().insert(ast_ty.id, def::PathResolution { - base_def: def, - depth: 0 - }); - } - - ty - } - hir::TyFixedLengthVec(ref ty, ref e) => { - let hint = UncheckedExprHint(tcx.types.usize); - match eval_const_expr_partial(tcx.global_tcx(), &e, hint, None) { - Ok(ConstVal::Integral(ConstInt::Usize(i))) => { - let i = i.as_u64(tcx.sess.target.uint_type); - assert_eq!(i as usize as u64, i); - tcx.mk_array(self.ast_ty_to_ty(rscope, &ty), i as usize) - }, - Ok(val) => { - span_err!(tcx.sess, ast_ty.span, E0249, - "expected usize value for array length, got {}", val.description()); - self.tcx().types.err - }, - // array length errors happen before the global constant check - // so we need to report the real error - Err(ConstEvalErr { kind: ErroneousReferencedConstant(box r), ..}) | - Err(r) => { - let mut err = struct_span_err!(tcx.sess, r.span, E0250, - "array length constant evaluation error: {}", - r.description()); - if !ast_ty.span.contains(r.span) { - span_note!(&mut err, ast_ty.span, "for array length here") + None => match rscope.anon_regions(default_span, 1) { + Ok(rs) => rs[0], + Err(params) => { + let mut err = struct_span_err!(self.tcx().sess, default_span, E0106, + "missing lifetime specifier"); + if let Some(params) = params { + report_elision_failure(&mut err, params); } err.emit(); - self.tcx().types.err - } - } - } - hir::TyTypeof(ref _e) => { - span_err!(tcx.sess, ast_ty.span, E0516, - "`typeof` is a reserved keyword but unimplemented"); - tcx.types.err - } - hir::TyInfer => { - // TyInfer also appears as the type of arguments or return - // values in a ExprClosure, or as - // the type of local variables. Both of these cases are - // handled specially and will not descend into this routine. - self.ty_infer(None, None, None, ast_ty.span) - } - } -} - -pub fn ty_of_arg(&self, - rscope: &RegionScope, - a: &hir::Arg, - expected_ty: Option>) - -> Ty<'tcx> -{ - match a.ty.node { - hir::TyInfer if expected_ty.is_some() => expected_ty.unwrap(), - hir::TyInfer => self.ty_infer(None, None, None, a.ty.span), - _ => self.ast_ty_to_ty(rscope, &a.ty), - } -} - -pub fn ty_of_method(&self, - sig: &hir::MethodSig, - untransformed_self_ty: Ty<'tcx>) - -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory) { - let self_info = Some(SelfInfo { - untransformed_self_ty: untransformed_self_ty, - explicit_self: &sig.explicit_self, - }); - let (bare_fn_ty, optional_explicit_self_category) = - self.ty_of_method_or_bare_fn(sig.unsafety, - sig.abi, - self_info, - &sig.decl); - (bare_fn_ty, optional_explicit_self_category.unwrap()) -} - -pub fn ty_of_bare_fn(&self, - unsafety: hir::Unsafety, abi: abi::Abi, - decl: &hir::FnDecl) - -> &'tcx ty::BareFnTy<'tcx> { - let (bare_fn_ty, _) = self.ty_of_method_or_bare_fn(unsafety, abi, None, decl); - bare_fn_ty -} - -fn ty_of_method_or_bare_fn<'a>(&self, - unsafety: hir::Unsafety, - abi: abi::Abi, - opt_self_info: Option>, - decl: &hir::FnDecl) - -> (&'tcx ty::BareFnTy<'tcx>, - Option) -{ - debug!("ty_of_method_or_bare_fn"); - - // New region names that appear inside of the arguments of the function - // declaration are bound to that function type. - let rb = rscope::BindingRscope::new(); - - // `implied_output_region` is the region that will be assumed for any - // region parameters in the return type. In accordance with the rules for - // lifetime elision, we can determine it in two ways. First (determined - // here), if self is by-reference, then the implied output region is the - // region of the self parameter. - let (self_ty, explicit_self_category) = match opt_self_info { - None => (None, None), - Some(self_info) => self.determine_self_type(&rb, self_info) - }; - - // HACK(eddyb) replace the fake self type in the AST with the actual type. - let arg_params = if self_ty.is_some() { - &decl.inputs[1..] - } else { - &decl.inputs[..] - }; - let arg_tys: Vec = - arg_params.iter().map(|a| self.ty_of_arg(&rb, a, None)).collect(); - let arg_pats: Vec = - arg_params.iter().map(|a| pprust::pat_to_string(&a.pat)).collect(); - - // Second, if there was exactly one lifetime (either a substitution or a - // reference) in the arguments, then any anonymous regions in the output - // have that lifetime. - let implied_output_region = match explicit_self_category { - Some(ty::ExplicitSelfCategory::ByReference(region, _)) => Ok(region), - _ => self.find_implied_output_region(&arg_tys, arg_pats) - }; - - let output_ty = match decl.output { - hir::Return(ref output) => - ty::FnConverging(self.convert_ty_with_lifetime_elision(implied_output_region, - &output)), - hir::DefaultReturn(..) => ty::FnConverging(self.tcx().mk_nil()), - hir::NoReturn(..) => ty::FnDiverging - }; - - (self.tcx().mk_bare_fn(ty::BareFnTy { - unsafety: unsafety, - abi: abi, - sig: ty::Binder(ty::FnSig { - inputs: self_ty.into_iter().chain(arg_tys).collect(), - output: output_ty, - variadic: decl.variadic - }), - }), explicit_self_category) -} - -fn determine_self_type<'a>(&self, - rscope: &RegionScope, - self_info: SelfInfo<'a, 'tcx>) - -> (Option>, Option) -{ - let self_ty = self_info.untransformed_self_ty; - return match self_info.explicit_self.node { - hir::SelfStatic => (None, Some(ty::ExplicitSelfCategory::Static)), - hir::SelfValue(_) => { - (Some(self_ty), Some(ty::ExplicitSelfCategory::ByValue)) - } - hir::SelfRegion(ref lifetime, mutability, _) => { - let region = - self.opt_ast_region_to_region(rscope, - self_info.explicit_self.span, - lifetime); - (Some(self.tcx().mk_ref( - self.tcx().mk_region(region), - ty::TypeAndMut { - ty: self_ty, - mutbl: mutability - })), - Some(ty::ExplicitSelfCategory::ByReference(region, mutability))) - } - hir::SelfExplicit(ref ast_type, _) => { - let explicit_type = self.ast_ty_to_ty(rscope, &ast_type); - - // We wish to (for now) categorize an explicit self - // declaration like `self: SomeType` into either `self`, - // `&self`, `&mut self`, or `Box`. We do this here - // by some simple pattern matching. A more precise check - // is done later in `check_method_self_type()`. - // - // Examples: - // - // ``` - // impl Foo for &T { - // // Legal declarations: - // fn method1(self: &&T); // ExplicitSelfCategory::ByReference - // fn method2(self: &T); // ExplicitSelfCategory::ByValue - // fn method3(self: Box<&T>); // ExplicitSelfCategory::ByBox - // - // // Invalid cases will be caught later by `check_method_self_type`: - // fn method_err1(self: &mut T); // ExplicitSelfCategory::ByReference - // } - // ``` - // - // To do the check we just count the number of "modifiers" - // on each type and compare them. If they are the same or - // the impl has more, we call it "by value". Otherwise, we - // look at the outermost modifier on the method decl and - // call it by-ref, by-box as appropriate. For method1, for - // example, the impl type has one modifier, but the method - // type has two, so we end up with - // ExplicitSelfCategory::ByReference. - - let impl_modifiers = count_modifiers(self_info.untransformed_self_ty); - let method_modifiers = count_modifiers(explicit_type); - - debug!("determine_explicit_self_category(self_info.untransformed_self_ty={:?} \ - explicit_type={:?} \ - modifiers=({},{})", - self_info.untransformed_self_ty, - explicit_type, - impl_modifiers, - method_modifiers); - - let category = if impl_modifiers >= method_modifiers { - ty::ExplicitSelfCategory::ByValue - } else { - match explicit_type.sty { - ty::TyRef(r, mt) => ty::ExplicitSelfCategory::ByReference(*r, mt.mutbl), - ty::TyBox(_) => ty::ExplicitSelfCategory::ByBox, - _ => ty::ExplicitSelfCategory::ByValue, - } - }; - - (Some(explicit_type), Some(category)) - } - }; - - fn count_modifiers(ty: Ty) -> usize { - match ty.sty { - ty::TyRef(_, mt) => count_modifiers(mt.ty) + 1, - ty::TyBox(t) => count_modifiers(t) + 1, - _ => 0, - } - } -} - -pub fn ty_of_closure(&self, - unsafety: hir::Unsafety, - decl: &hir::FnDecl, - abi: abi::Abi, - expected_sig: Option>) - -> ty::ClosureTy<'tcx> -{ - debug!("ty_of_closure(expected_sig={:?})", - expected_sig); - - // new region names that appear inside of the fn decl are bound to - // that function type - let rb = rscope::BindingRscope::new(); - - let input_tys: Vec<_> = decl.inputs.iter().enumerate().map(|(i, a)| { - let expected_arg_ty = expected_sig.as_ref().and_then(|e| { - // no guarantee that the correct number of expected args - // were supplied - if i < e.inputs.len() { - Some(e.inputs[i]) - } else { - None - } - }); - self.ty_of_arg(&rb, a, expected_arg_ty) - }).collect(); - - let expected_ret_ty = expected_sig.map(|e| e.output); - - let is_infer = match decl.output { - hir::Return(ref output) if output.node == hir::TyInfer => true, - hir::DefaultReturn(..) => true, - _ => false - }; - - let output_ty = match decl.output { - _ if is_infer && expected_ret_ty.is_some() => - expected_ret_ty.unwrap(), - _ if is_infer => - ty::FnConverging(self.ty_infer(None, None, None, decl.output.span())), - hir::Return(ref output) => - ty::FnConverging(self.ast_ty_to_ty(&rb, &output)), - hir::DefaultReturn(..) => bug!(), - hir::NoReturn(..) => ty::FnDiverging - }; - - debug!("ty_of_closure: input_tys={:?}", input_tys); - debug!("ty_of_closure: output_ty={:?}", output_ty); - - ty::ClosureTy { - unsafety: unsafety, - abi: abi, - sig: ty::Binder(ty::FnSig {inputs: input_tys, - output: output_ty, - variadic: decl.variadic}), - } -} - -/// Given an existential type like `Foo+'a+Bar`, this routine converts the `'a` and `Bar` intos an -/// `ExistentialBounds` struct. The `main_trait_refs` argument specifies the `Foo` -- it is absent -/// for closures. Eventually this should all be normalized, I think, so that there is no "main -/// trait ref" and instead we just have a flat list of bounds as the existential type. -fn conv_existential_bounds(&self, - rscope: &RegionScope, - span: Span, - principal_trait_ref: ty::PolyTraitRef<'tcx>, - projection_bounds: Vec>, - ast_bounds: &[hir::TyParamBound]) - -> ty::ExistentialBounds<'tcx> -{ - let partitioned_bounds = - partition_bounds(self.tcx(), span, ast_bounds); - - self.conv_existential_bounds_from_partitioned_bounds( - rscope, span, principal_trait_ref, projection_bounds, partitioned_bounds) -} - -fn conv_ty_poly_trait_ref(&self, - rscope: &RegionScope, - span: Span, - ast_bounds: &[hir::TyParamBound]) - -> Ty<'tcx> -{ - let mut partitioned_bounds = partition_bounds(self.tcx(), span, &ast_bounds[..]); - - let mut projection_bounds = Vec::new(); - let main_trait_bound = if !partitioned_bounds.trait_bounds.is_empty() { - let trait_bound = partitioned_bounds.trait_bounds.remove(0); - self.instantiate_poly_trait_ref(rscope, - trait_bound, - None, - &mut projection_bounds) - } else { - span_err!(self.tcx().sess, span, E0224, - "at least one non-builtin trait is required for an object type"); - return self.tcx().types.err; - }; - - let bounds = - self.conv_existential_bounds_from_partitioned_bounds(rscope, - span, - main_trait_bound.clone(), - projection_bounds, - partitioned_bounds); - - self.make_object_type(span, main_trait_bound, bounds) -} - -pub fn conv_existential_bounds_from_partitioned_bounds(&self, - rscope: &RegionScope, - span: Span, - principal_trait_ref: ty::PolyTraitRef<'tcx>, - projection_bounds: Vec>, // Empty for boxed closures - partitioned_bounds: PartitionedBounds) - -> ty::ExistentialBounds<'tcx> -{ - let PartitionedBounds { builtin_bounds, - trait_bounds, - region_bounds } = - partitioned_bounds; - - if !trait_bounds.is_empty() { - let b = &trait_bounds[0]; - span_err!(self.tcx().sess, b.trait_ref.path.span, E0225, - "only the builtin traits can be used as closure or object bounds"); - } - - let region_bound = - self.compute_object_lifetime_bound(span, - ®ion_bounds, - principal_trait_ref, - builtin_bounds); - - let region_bound = match region_bound { - Some(r) => r, - None => { - match rscope.object_lifetime_default(span) { - Some(r) => r, - None => { - span_err!(self.tcx().sess, span, E0228, - "the lifetime bound for this object type cannot be deduced \ - from context; please supply an explicit bound"); ty::ReStatic } } + }; + + debug!("opt_ast_region_to_region(opt_lifetime={:?}) yields {:?}", + opt_lifetime, + r); + + r + } + + /// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`, + /// returns an appropriate set of substitutions for this particular reference to `I`. + pub fn ast_path_substs_for_ty(&self, + rscope: &RegionScope, + span: Span, + param_mode: PathParamMode, + decl_generics: &ty::Generics<'tcx>, + item_segment: &hir::PathSegment) + -> Substs<'tcx> + { + let tcx = self.tcx(); + + // ast_path_substs() is only called to convert paths that are + // known to refer to traits, types, or structs. In these cases, + // all type parameters defined for the item being referenced will + // be in the TypeSpace or SelfSpace. + // + // Note: in the case of traits, the self parameter is also + // defined, but we don't currently create a `type_param_def` for + // `Self` because it is implicit. + assert!(decl_generics.regions.all(|d| d.space == TypeSpace)); + assert!(decl_generics.types.all(|d| d.space != FnSpace)); + + let (regions, types, assoc_bindings) = match item_segment.parameters { + hir::AngleBracketedParameters(ref data) => { + self.convert_angle_bracketed_parameters(rscope, span, decl_generics, data) + } + hir::ParenthesizedParameters(..) => { + span_err!(tcx.sess, span, E0214, + "parenthesized parameters may only be used with a trait"); + let ty_param_defs = decl_generics.types.get_slice(TypeSpace); + (Substs::empty(), + ty_param_defs.iter().map(|_| tcx.types.err).collect(), + vec![]) + } + }; + + assoc_bindings.first().map(|b| self.tcx().prohibit_projection(b.span)); + + self.create_substs_for_ast_path(span, + param_mode, + decl_generics, + None, + types, + regions) + } + + fn create_region_substs(&self, + rscope: &RegionScope, + span: Span, + decl_generics: &ty::Generics<'tcx>, + regions_provided: Vec) + -> Substs<'tcx> + { + let tcx = self.tcx(); + + // If the type is parameterized by this region, then replace this + // region with the current anon region binding (in other words, + // whatever & would get replaced with). + let expected_num_region_params = decl_generics.regions.len(TypeSpace); + let supplied_num_region_params = regions_provided.len(); + let regions = if expected_num_region_params == supplied_num_region_params { + regions_provided + } else { + let anon_regions = + rscope.anon_regions(span, expected_num_region_params); + + if supplied_num_region_params != 0 || anon_regions.is_err() { + report_lifetime_number_error(tcx, span, + supplied_num_region_params, + expected_num_region_params); + } + + match anon_regions { + Ok(anon_regions) => anon_regions, + Err(_) => (0..expected_num_region_params).map(|_| ty::ReStatic).collect() + } + }; + Substs::new_type(vec![], regions) + } + + /// Given the type/region arguments provided to some path (along with + /// an implicit Self, if this is a trait reference) returns the complete + /// set of substitutions. This may involve applying defaulted type parameters. + /// + /// Note that the type listing given here is *exactly* what the user provided. + /// + /// The `region_substs` should be the result of `create_region_substs` + /// -- that is, a substitution with no types but the correct number of + /// regions. + fn create_substs_for_ast_path(&self, + span: Span, + param_mode: PathParamMode, + decl_generics: &ty::Generics<'tcx>, + self_ty: Option>, + types_provided: Vec>, + region_substs: Substs<'tcx>) + -> Substs<'tcx> + { + let tcx = self.tcx(); + + debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}, \ + types_provided={:?}, region_substs={:?})", + decl_generics, self_ty, types_provided, + region_substs); + + assert_eq!(region_substs.regions.len(TypeSpace), decl_generics.regions.len(TypeSpace)); + assert!(region_substs.types.is_empty()); + + // Convert the type parameters supplied by the user. + let ty_param_defs = decl_generics.types.get_slice(TypeSpace); + let formal_ty_param_count = ty_param_defs.len(); + let required_ty_param_count = ty_param_defs.iter() + .take_while(|x| x.default.is_none()) + .count(); + + let mut type_substs = self.get_type_substs_for_defs(span, + types_provided, + param_mode, + ty_param_defs, + region_substs.clone(), + self_ty); + + let supplied_ty_param_count = type_substs.len(); + check_type_argument_count(self.tcx(), span, supplied_ty_param_count, + required_ty_param_count, formal_ty_param_count); + + if supplied_ty_param_count < required_ty_param_count { + while type_substs.len() < required_ty_param_count { + type_substs.push(tcx.types.err); + } + } else if supplied_ty_param_count > formal_ty_param_count { + type_substs.truncate(formal_ty_param_count); } - }; + assert!(type_substs.len() >= required_ty_param_count && + type_substs.len() <= formal_ty_param_count); - debug!("region_bound: {:?}", region_bound); + let mut substs = region_substs; + substs.types.extend(TypeSpace, type_substs.into_iter()); - ty::ExistentialBounds::new(region_bound, builtin_bounds, projection_bounds) -} + match self_ty { + None => { + // If no self-type is provided, it's still possible that + // one was declared, because this could be an object type. + } + Some(ty) => { + // If a self-type is provided, one should have been + // "declared" (in other words, this should be a + // trait-ref). + assert!(decl_generics.types.get_self().is_some()); + substs.types.push(SelfSpace, ty); + } + } -/// Given the bounds on an object, determines what single region bound -/// (if any) we can use to summarize this type. The basic idea is that we will use the bound the -/// user provided, if they provided one, and otherwise search the supertypes of trait bounds for -/// region bounds. It may be that we can derive no bound at all, in which case we return `None`. -fn compute_object_lifetime_bound(&self, - span: Span, - explicit_region_bounds: &[&hir::Lifetime], - principal_trait_ref: ty::PolyTraitRef<'tcx>, - builtin_bounds: ty::BuiltinBounds) - -> Option // if None, use the default -{ - let tcx = self.tcx(); + let actual_supplied_ty_param_count = substs.types.len(TypeSpace); + for param in &ty_param_defs[actual_supplied_ty_param_count..] { + if let Some(default) = param.default { + // If we are converting an object type, then the + // `Self` parameter is unknown. However, some of the + // other type parameters may reference `Self` in their + // defaults. This will lead to an ICE if we are not + // careful! + if self_ty.is_none() && default.has_self_ty() { + span_err!(tcx.sess, span, E0393, + "the type parameter `{}` must be explicitly specified \ + in an object type because its default value `{}` references \ + the type `Self`", + param.name, + default); + substs.types.push(TypeSpace, tcx.types.err); + } else { + // This is a default type parameter. + let default = default.subst_spanned(tcx, + &substs, + Some(span)); + substs.types.push(TypeSpace, default); + } + } else { + span_bug!(span, "extra parameter without default"); + } + } - debug!("compute_opt_region_bound(explicit_region_bounds={:?}, \ - principal_trait_ref={:?}, builtin_bounds={:?})", - explicit_region_bounds, - principal_trait_ref, - builtin_bounds); + debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}) -> {:?}", + decl_generics, self_ty, substs); - if explicit_region_bounds.len() > 1 { - span_err!(tcx.sess, explicit_region_bounds[1].span, E0226, - "only a single explicit lifetime bound is permitted"); + substs } - if !explicit_region_bounds.is_empty() { - // Explicitly specified region bound. Use that. - let r = explicit_region_bounds[0]; - return Some(ast_region_to_region(tcx, r)); + /// Returns types_provided if it is not empty, otherwise populating the + /// type parameters with inference variables as appropriate. + fn get_type_substs_for_defs(&self, + span: Span, + types_provided: Vec>, + param_mode: PathParamMode, + ty_param_defs: &[ty::TypeParameterDef<'tcx>], + mut substs: Substs<'tcx>, + self_ty: Option>) + -> Vec> + { + fn default_type_parameter<'tcx>(p: &ty::TypeParameterDef<'tcx>, self_ty: Option>) + -> Option> + { + if let Some(ref default) = p.default { + if self_ty.is_none() && default.has_self_ty() { + // There is no suitable inference default for a type parameter + // that references self with no self-type provided. + return None; + } + } + + Some(p.clone()) + } + + if param_mode == PathParamMode::Optional && types_provided.is_empty() { + ty_param_defs + .iter() + .map(|p| self.ty_infer(default_type_parameter(p, self_ty), Some(&mut substs), + Some(TypeSpace), span)) + .collect() + } else { + types_provided + } } - if let Err(ErrorReported) = self.ensure_super_predicates(span,principal_trait_ref.def_id()) { - return Some(ty::ReStatic); + fn convert_angle_bracketed_parameters(&self, + rscope: &RegionScope, + span: Span, + decl_generics: &ty::Generics<'tcx>, + data: &hir::AngleBracketedParameterData) + -> (Substs<'tcx>, + Vec>, + Vec>) + { + let regions: Vec<_> = + data.lifetimes.iter() + .map(|l| ast_region_to_region(self.tcx(), l)) + .collect(); + + let region_substs = + self.create_region_substs(rscope, span, decl_generics, regions); + + let types: Vec<_> = + data.types.iter() + .enumerate() + .map(|(i,t)| self.ast_ty_arg_to_ty(rscope, decl_generics, + i, ®ion_substs, t)) + .collect(); + + let assoc_bindings: Vec<_> = + data.bindings.iter() + .map(|b| ConvertedBinding { item_name: b.name, + ty: self.ast_ty_to_ty(rscope, &b.ty), + span: b.span }) + .collect(); + + (region_substs, types, assoc_bindings) } - // No explicit region bound specified. Therefore, examine trait - // bounds and see if we can derive region bounds from those. - let derived_region_bounds = - object_region_bounds(tcx, &principal_trait_ref, builtin_bounds); + /// Returns the appropriate lifetime to use for any output lifetimes + /// (if one exists) and a vector of the (pattern, number of lifetimes) + /// corresponding to each input type/pattern. + fn find_implied_output_region(&self, + input_tys: &[Ty<'tcx>], + input_pats: Vec) -> ElidedLifetime + { + let tcx = self.tcx(); + let mut lifetimes_for_params = Vec::new(); + let mut possible_implied_output_region = None; - // If there are no derived region bounds, then report back that we - // can find no region bound. The caller will use the default. - if derived_region_bounds.is_empty() { - return None; + for (input_type, input_pat) in input_tys.iter().zip(input_pats) { + let mut regions = FnvHashSet(); + let have_bound_regions = tcx.collect_regions(input_type, &mut regions); + + debug!("find_implied_output_regions: collected {:?} from {:?} \ + have_bound_regions={:?}", ®ions, input_type, have_bound_regions); + + if regions.len() == 1 { + // there's a chance that the unique lifetime of this + // iteration will be the appropriate lifetime for output + // parameters, so lets store it. + possible_implied_output_region = regions.iter().cloned().next(); + } + + lifetimes_for_params.push(ElisionFailureInfo { + name: input_pat, + lifetime_count: regions.len(), + have_bound_regions: have_bound_regions + }); + } + + if lifetimes_for_params.iter().map(|e| e.lifetime_count).sum::() == 1 { + Ok(possible_implied_output_region.unwrap()) + } else { + Err(Some(lifetimes_for_params)) + } } - // If any of the derived region bounds are 'static, that is always - // the best choice. - if derived_region_bounds.iter().any(|r| ty::ReStatic == *r) { - return Some(ty::ReStatic); + fn convert_ty_with_lifetime_elision(&self, + elided_lifetime: ElidedLifetime, + ty: &hir::Ty) + -> Ty<'tcx> + { + match elided_lifetime { + Ok(implied_output_region) => { + let rb = ElidableRscope::new(implied_output_region); + self.ast_ty_to_ty(&rb, ty) + } + Err(param_lifetimes) => { + // All regions must be explicitly specified in the output + // if the lifetime elision rules do not apply. This saves + // the user from potentially-confusing errors. + let rb = UnelidableRscope::new(param_lifetimes); + self.ast_ty_to_ty(&rb, ty) + } + } } - // Determine whether there is exactly one unique region in the set - // of derived region bounds. If so, use that. Otherwise, report an - // error. - let r = derived_region_bounds[0]; - if derived_region_bounds[1..].iter().any(|r1| r != *r1) { - span_err!(tcx.sess, span, E0227, - "ambiguous lifetime bound, explicit lifetime bound required"); + fn convert_parenthesized_parameters(&self, + rscope: &RegionScope, + span: Span, + decl_generics: &ty::Generics<'tcx>, + data: &hir::ParenthesizedParameterData) + -> (Substs<'tcx>, + Vec>, + Vec>) + { + let region_substs = + self.create_region_substs(rscope, span, decl_generics, Vec::new()); + + let binding_rscope = BindingRscope::new(); + let inputs = + data.inputs.iter() + .map(|a_t| self.ast_ty_arg_to_ty(&binding_rscope, decl_generics, + 0, ®ion_substs, a_t)) + .collect::>>(); + + let input_params = vec![String::new(); inputs.len()]; + let implied_output_region = self.find_implied_output_region(&inputs, input_params); + + let input_ty = self.tcx().mk_tup(inputs); + + let (output, output_span) = match data.output { + Some(ref output_ty) => { + (self.convert_ty_with_lifetime_elision(implied_output_region, &output_ty), + output_ty.span) + } + None => { + (self.tcx().mk_nil(), data.span) + } + }; + + let output_binding = ConvertedBinding { + item_name: token::intern(FN_OUTPUT_NAME), + ty: output, + span: output_span + }; + + (region_substs, vec![input_ty], vec![output_binding]) + } + + pub fn instantiate_poly_trait_ref(&self, + rscope: &RegionScope, + ast_trait_ref: &hir::PolyTraitRef, + self_ty: Option>, + poly_projections: &mut Vec>) + -> ty::PolyTraitRef<'tcx> + { + let trait_ref = &ast_trait_ref.trait_ref; + let trait_def_id = self.trait_def_id(trait_ref); + self.ast_path_to_poly_trait_ref(rscope, + trait_ref.path.span, + PathParamMode::Explicit, + trait_def_id, + self_ty, + trait_ref.path.segments.last().unwrap(), + poly_projections) + } + + /// Instantiates the path for the given trait reference, assuming that it's + /// bound to a valid trait type. Returns the def_id for the defining trait. + /// Fails if the type is a type other than a trait type. + /// + /// If the `projections` argument is `None`, then assoc type bindings like `Foo` + /// are disallowed. Otherwise, they are pushed onto the vector given. + pub fn instantiate_mono_trait_ref(&self, + rscope: &RegionScope, + trait_ref: &hir::TraitRef, + self_ty: Option>) + -> ty::TraitRef<'tcx> + { + let trait_def_id = self.trait_def_id(trait_ref); + self.ast_path_to_mono_trait_ref(rscope, + trait_ref.path.span, + PathParamMode::Explicit, + trait_def_id, + self_ty, + trait_ref.path.segments.last().unwrap()) + } + + fn trait_def_id(&self, trait_ref: &hir::TraitRef) -> DefId { + let path = &trait_ref.path; + match ::lookup_full_def(self.tcx(), path.span, trait_ref.ref_id) { + Def::Trait(trait_def_id) => trait_def_id, + Def::Err => { + self.tcx().sess.fatal("cannot continue compilation due to previous error"); + } + _ => { + span_fatal!(self.tcx().sess, path.span, E0245, "`{}` is not a trait", + path); + } + } + } + + fn object_path_to_poly_trait_ref(&self, + rscope: &RegionScope, + span: Span, + param_mode: PathParamMode, + trait_def_id: DefId, + trait_segment: &hir::PathSegment, + mut projections: &mut Vec>) + -> ty::PolyTraitRef<'tcx> + { + self.ast_path_to_poly_trait_ref(rscope, + span, + param_mode, + trait_def_id, + None, + trait_segment, + projections) + } + + fn ast_path_to_poly_trait_ref(&self, + rscope: &RegionScope, + span: Span, + param_mode: PathParamMode, + trait_def_id: DefId, + self_ty: Option>, + trait_segment: &hir::PathSegment, + poly_projections: &mut Vec>) + -> ty::PolyTraitRef<'tcx> + { + debug!("ast_path_to_poly_trait_ref(trait_segment={:?})", trait_segment); + // The trait reference introduces a binding level here, so + // we need to shift the `rscope`. It'd be nice if we could + // do away with this rscope stuff and work this knowledge + // into resolve_lifetimes, as we do with non-omitted + // lifetimes. Oh well, not there yet. + let shifted_rscope = &ShiftedRscope::new(rscope); + + let (substs, assoc_bindings) = + self.create_substs_for_ast_trait_ref(shifted_rscope, + span, + param_mode, + trait_def_id, + self_ty, + trait_segment); + let poly_trait_ref = ty::Binder(ty::TraitRef::new(trait_def_id, substs)); + + { + let converted_bindings = + assoc_bindings + .iter() + .filter_map(|binding| { + // specify type to assert that error was already reported in Err case: + let predicate: Result<_, ErrorReported> = + self.ast_type_binding_to_poly_projection_predicate(poly_trait_ref.clone(), + self_ty, + binding); + predicate.ok() // ok to ignore Err() because ErrorReported (see above) + }); + poly_projections.extend(converted_bindings); + } + + debug!("ast_path_to_poly_trait_ref(trait_segment={:?}, projections={:?}) -> {:?}", + trait_segment, poly_projections, poly_trait_ref); + poly_trait_ref + } + + fn ast_path_to_mono_trait_ref(&self, + rscope: &RegionScope, + span: Span, + param_mode: PathParamMode, + trait_def_id: DefId, + self_ty: Option>, + trait_segment: &hir::PathSegment) + -> ty::TraitRef<'tcx> + { + let (substs, assoc_bindings) = + self.create_substs_for_ast_trait_ref(rscope, + span, + param_mode, + trait_def_id, + self_ty, + trait_segment); + assoc_bindings.first().map(|b| self.tcx().prohibit_projection(b.span)); + ty::TraitRef::new(trait_def_id, substs) + } + + fn create_substs_for_ast_trait_ref(&self, + rscope: &RegionScope, + span: Span, + param_mode: PathParamMode, + trait_def_id: DefId, + self_ty: Option>, + trait_segment: &hir::PathSegment) + -> (&'tcx Substs<'tcx>, Vec>) + { + debug!("create_substs_for_ast_trait_ref(trait_segment={:?})", + trait_segment); + + let trait_def = match self.get_trait_def(span, trait_def_id) { + Ok(trait_def) => trait_def, + Err(ErrorReported) => { + // No convenient way to recover from a cycle here. Just bail. Sorry! + self.tcx().sess.abort_if_errors(); + bug!("ErrorReported returned, but no errors reports?") + } + }; + + let (regions, types, assoc_bindings) = match trait_segment.parameters { + hir::AngleBracketedParameters(ref data) => { + // For now, require that parenthetical notation be used + // only with `Fn()` etc. + if !self.tcx().sess.features.borrow().unboxed_closures && trait_def.paren_sugar { + emit_feature_err(&self.tcx().sess.parse_sess.span_diagnostic, + "unboxed_closures", span, GateIssue::Language, + "\ + the precise format of `Fn`-family traits' \ + type parameters is subject to change. \ + Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead"); + } + + self.convert_angle_bracketed_parameters(rscope, span, &trait_def.generics, data) + } + hir::ParenthesizedParameters(ref data) => { + // For now, require that parenthetical notation be used + // only with `Fn()` etc. + if !self.tcx().sess.features.borrow().unboxed_closures && !trait_def.paren_sugar { + emit_feature_err(&self.tcx().sess.parse_sess.span_diagnostic, + "unboxed_closures", span, GateIssue::Language, + "\ + parenthetical notation is only stable when used with `Fn`-family traits"); + } + + self.convert_parenthesized_parameters(rscope, span, &trait_def.generics, data) + } + }; + + let substs = self.create_substs_for_ast_path(span, + param_mode, + &trait_def.generics, + self_ty, + types, + regions); + + (self.tcx().mk_substs(substs), assoc_bindings) + } + + fn ast_type_binding_to_poly_projection_predicate(&self, + mut trait_ref: ty::PolyTraitRef<'tcx>, + self_ty: Option>, + binding: &ConvertedBinding<'tcx>) + -> Result, ErrorReported> + { + let tcx = self.tcx(); + + // Given something like `U : SomeTrait`, we want to produce a + // predicate like `::T = X`. This is somewhat + // subtle in the event that `T` is defined in a supertrait of + // `SomeTrait`, because in that case we need to upcast. + // + // That is, consider this case: + // + // ``` + // trait SubTrait : SuperTrait { } + // trait SuperTrait { type T; } + // + // ... B : SubTrait ... + // ``` + // + // We want to produce `>::T == foo`. + + // Simple case: X is defined in the current trait. + if self.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) { + return Ok(ty::Binder(ty::ProjectionPredicate { // <-------------------+ + projection_ty: ty::ProjectionTy { // | + trait_ref: trait_ref.skip_binder().clone(), // Binder moved here --+ + item_name: binding.item_name, + }, + ty: binding.ty, + })); + } + + // Otherwise, we have to walk through the supertraits to find + // those that do. This is complicated by the fact that, for an + // object type, the `Self` type is not present in the + // substitutions (after all, it's being constructed right now), + // but the `supertraits` iterator really wants one. To handle + // this, we currently insert a dummy type and then remove it + // later. Yuck. + + let dummy_self_ty = tcx.mk_infer(ty::FreshTy(0)); + if self_ty.is_none() { // if converting for an object type + let mut dummy_substs = trait_ref.skip_binder().substs.clone(); // binder moved here -+ + assert!(dummy_substs.self_ty().is_none()); // | + dummy_substs.types.push(SelfSpace, dummy_self_ty); // | + trait_ref = ty::Binder(ty::TraitRef::new(trait_ref.def_id(), // <------------+ + tcx.mk_substs(dummy_substs))); + } + + self.ensure_super_predicates(binding.span, trait_ref.def_id())?; + + let mut candidates: Vec = + traits::supertraits(tcx, trait_ref.clone()) + .filter(|r| self.trait_defines_associated_type_named(r.def_id(), binding.item_name)) + .collect(); + + // If converting for an object type, then remove the dummy-ty from `Self` now. + // Yuckety yuck. + if self_ty.is_none() { + for candidate in &mut candidates { + let mut dummy_substs = candidate.0.substs.clone(); + assert!(dummy_substs.self_ty() == Some(dummy_self_ty)); + dummy_substs.types.pop(SelfSpace); + *candidate = ty::Binder(ty::TraitRef::new(candidate.def_id(), + tcx.mk_substs(dummy_substs))); + } + } + + let candidate = self.one_bound_for_assoc_type(candidates, + &trait_ref.to_string(), + &binding.item_name.as_str(), + binding.span)?; + + Ok(ty::Binder(ty::ProjectionPredicate { // <-------------------------+ + projection_ty: ty::ProjectionTy { // | + trait_ref: candidate.skip_binder().clone(), // binder is moved up here --+ + item_name: binding.item_name, + }, + ty: binding.ty, + })) + } + + fn ast_path_to_ty(&self, + rscope: &RegionScope, + span: Span, + param_mode: PathParamMode, + did: DefId, + item_segment: &hir::PathSegment) + -> Ty<'tcx> + { + let tcx = self.tcx(); + let (generics, decl_ty) = match self.get_item_type_scheme(span, did) { + Ok(ty::TypeScheme { generics, ty: decl_ty }) => { + (generics, decl_ty) + } + Err(ErrorReported) => { + return tcx.types.err; + } + }; + + let substs = self.ast_path_substs_for_ty(rscope, + span, + param_mode, + &generics, + item_segment); + + // FIXME(#12938): This is a hack until we have full support for DST. + if Some(did) == self.tcx().lang_items.owned_box() { + assert_eq!(substs.types.len(TypeSpace), 1); + return self.tcx().mk_box(*substs.types.get(TypeSpace, 0)); + } + + decl_ty.subst(self.tcx(), &substs) + } + + fn ast_ty_to_trait_ref(&self, + rscope: &RegionScope, + ty: &hir::Ty, + bounds: &[hir::TyParamBound]) + -> Result, ErrorReported> + { + /*! + * In a type like `Foo + Send`, we want to wait to collect the + * full set of bounds before we make the object type, because we + * need them to infer a region bound. (For example, if we tried + * made a type from just `Foo`, then it wouldn't be enough to + * infer a 'static bound, and hence the user would get an error.) + * So this function is used when we're dealing with a sum type to + * convert the LHS. It only accepts a type that refers to a trait + * name, and reports an error otherwise. + */ + + match ty.node { + hir::TyPath(None, ref path) => { + let def = match self.tcx().def_map.borrow().get(&ty.id) { + Some(&def::PathResolution { base_def, depth: 0, .. }) => Some(base_def), + _ => None + }; + match def { + Some(Def::Trait(trait_def_id)) => { + let mut projection_bounds = Vec::new(); + let trait_ref = + self.object_path_to_poly_trait_ref(rscope, + path.span, + PathParamMode::Explicit, + trait_def_id, + path.segments.last().unwrap(), + &mut projection_bounds); + Ok((trait_ref, projection_bounds)) + } + _ => { + span_err!(self.tcx().sess, ty.span, E0172, + "expected a reference to a trait"); + Err(ErrorReported) + } + } + } + _ => { + let mut err = struct_span_err!(self.tcx().sess, ty.span, E0178, + "expected a path on the left-hand side \ + of `+`, not `{}`", + pprust::ty_to_string(ty)); + let hi = bounds.iter().map(|x| match *x { + hir::TraitTyParamBound(ref tr, _) => tr.span.hi, + hir::RegionTyParamBound(ref r) => r.span.hi, + }).max_by_key(|x| x.to_usize()); + let full_span = hi.map(|hi| Span { + lo: ty.span.lo, + hi: hi, + expn_id: ty.span.expn_id, + }); + match (&ty.node, full_span) { + (&hir::TyRptr(None, ref mut_ty), Some(full_span)) => { + let mutbl_str = if mut_ty.mutbl == hir::MutMutable { "mut " } else { "" }; + err.span_suggestion(full_span, "try adding parentheses (per RFC 438):", + format!("&{}({} +{})", + mutbl_str, + pprust::ty_to_string(&mut_ty.ty), + pprust::bounds_to_string(bounds))); + } + (&hir::TyRptr(Some(ref lt), ref mut_ty), Some(full_span)) => { + let mutbl_str = if mut_ty.mutbl == hir::MutMutable { "mut " } else { "" }; + err.span_suggestion(full_span, "try adding parentheses (per RFC 438):", + format!("&{} {}({} +{})", + pprust::lifetime_to_string(lt), + mutbl_str, + pprust::ty_to_string(&mut_ty.ty), + pprust::bounds_to_string(bounds))); + } + + _ => { + help!(&mut err, + "perhaps you forgot parentheses? (per RFC 438)"); + } + } + err.emit(); + Err(ErrorReported) + } + } + } + + fn trait_ref_to_object_type(&self, + rscope: &RegionScope, + span: Span, + trait_ref: ty::PolyTraitRef<'tcx>, + projection_bounds: Vec>, + bounds: &[hir::TyParamBound]) + -> Ty<'tcx> + { + let existential_bounds = self.conv_existential_bounds(rscope, + span, + trait_ref.clone(), + projection_bounds, + bounds); + + let result = self.make_object_type(span, trait_ref, existential_bounds); + debug!("trait_ref_to_object_type: result={:?}", + result); + + result + } + + fn make_object_type(&self, + span: Span, + principal: ty::PolyTraitRef<'tcx>, + bounds: ty::ExistentialBounds<'tcx>) + -> Ty<'tcx> { + let tcx = self.tcx(); + let object = ty::TraitTy { + principal: principal, + bounds: bounds + }; + let object_trait_ref = + object.principal_trait_ref_with_self_ty(tcx, tcx.types.err); + + // ensure the super predicates and stop if we encountered an error + if self.ensure_super_predicates(span, principal.def_id()).is_err() { + return tcx.types.err; + } + + // check that there are no gross object safety violations, + // most importantly, that the supertraits don't contain Self, + // to avoid ICE-s. + let object_safety_violations = + tcx.astconv_object_safety_violations(principal.def_id()); + if !object_safety_violations.is_empty() { + tcx.report_object_safety_error( + span, principal.def_id(), None, object_safety_violations) + .unwrap().emit(); + return tcx.types.err; + } + + let mut associated_types: FnvHashSet<(DefId, ast::Name)> = + traits::supertraits(tcx, object_trait_ref) + .flat_map(|tr| { + let trait_def = tcx.lookup_trait_def(tr.def_id()); + trait_def.associated_type_names + .clone() + .into_iter() + .map(move |associated_type_name| (tr.def_id(), associated_type_name)) + }) + .collect(); + + for projection_bound in &object.bounds.projection_bounds { + let pair = (projection_bound.0.projection_ty.trait_ref.def_id, + projection_bound.0.projection_ty.item_name); + associated_types.remove(&pair); + } + + for (trait_def_id, name) in associated_types { + span_err!(tcx.sess, span, E0191, + "the value of the associated type `{}` (from the trait `{}`) must be specified", + name, + tcx.item_path_str(trait_def_id)); + } + + tcx.mk_trait(object.principal, object.bounds) + } + + fn report_ambiguous_associated_type(&self, + span: Span, + type_str: &str, + trait_str: &str, + name: &str) { + span_err!(self.tcx().sess, span, E0223, + "ambiguous associated type; specify the type using the syntax \ + `<{} as {}>::{}`", + type_str, trait_str, name); + } + + // Search for a bound on a type parameter which includes the associated item + // given by assoc_name. ty_param_node_id is the node id for the type parameter + // (which might be `Self`, but only if it is the `Self` of a trait, not an + // impl). This function will fail if there are no suitable bounds or there is + // any ambiguity. + fn find_bound_for_assoc_item(&self, + ty_param_node_id: ast::NodeId, + ty_param_name: ast::Name, + assoc_name: ast::Name, + span: Span) + -> Result, ErrorReported> + { + let tcx = self.tcx(); + + let bounds = match self.get_type_parameter_bounds(span, ty_param_node_id) { + Ok(v) => v, + Err(ErrorReported) => { + return Err(ErrorReported); + } + }; + + // Ensure the super predicates and stop if we encountered an error. + if bounds.iter().any(|b| self.ensure_super_predicates(span, b.def_id()).is_err()) { + return Err(ErrorReported); + } + + // Check that there is exactly one way to find an associated type with the + // correct name. + let suitable_bounds: Vec<_> = + traits::transitive_bounds(tcx, &bounds) + .filter(|b| self.trait_defines_associated_type_named(b.def_id(), assoc_name)) + .collect(); + + self.one_bound_for_assoc_type(suitable_bounds, + &ty_param_name.as_str(), + &assoc_name.as_str(), + span) + } + + + // Checks that bounds contains exactly one element and reports appropriate + // errors otherwise. + fn one_bound_for_assoc_type(&self, + bounds: Vec>, + ty_param_name: &str, + assoc_name: &str, + span: Span) + -> Result, ErrorReported> + { + if bounds.is_empty() { + span_err!(self.tcx().sess, span, E0220, + "associated type `{}` not found for `{}`", + assoc_name, + ty_param_name); + return Err(ErrorReported); + } + + if bounds.len() > 1 { + let mut err = struct_span_err!(self.tcx().sess, span, E0221, + "ambiguous associated type `{}` in bounds of `{}`", + assoc_name, + ty_param_name); + + for bound in &bounds { + span_note!(&mut err, span, + "associated type `{}` could derive from `{}`", + ty_param_name, + bound); + } + err.emit(); + } + + Ok(bounds[0].clone()) + } + + // Create a type from a path to an associated type. + // For a path A::B::C::D, ty and ty_path_def are the type and def for A::B::C + // and item_segment is the path segment for D. We return a type and a def for + // the whole path. + // Will fail except for T::A and Self::A; i.e., if ty/ty_path_def are not a type + // parameter or Self. + fn associated_path_def_to_ty(&self, + span: Span, + ty: Ty<'tcx>, + ty_path_def: Def, + item_segment: &hir::PathSegment) + -> (Ty<'tcx>, Def) + { + let tcx = self.tcx(); + let assoc_name = item_segment.identifier.name; + + debug!("associated_path_def_to_ty: {:?}::{}", ty, assoc_name); + + tcx.prohibit_type_params(slice::ref_slice(item_segment)); + + // Find the type of the associated item, and the trait where the associated + // item is declared. + let bound = match (&ty.sty, ty_path_def) { + (_, Def::SelfTy(Some(trait_did), Some(impl_id))) => { + // `Self` in an impl of a trait - we have a concrete self type and a + // trait reference. + let trait_ref = tcx.impl_trait_ref(tcx.map.local_def_id(impl_id)).unwrap(); + let trait_ref = if let Some(free_substs) = self.get_free_substs() { + trait_ref.subst(tcx, free_substs) + } else { + trait_ref + }; + + if self.ensure_super_predicates(span, trait_did).is_err() { + return (tcx.types.err, ty_path_def); + } + + let candidates: Vec = + traits::supertraits(tcx, ty::Binder(trait_ref)) + .filter(|r| self.trait_defines_associated_type_named(r.def_id(), + assoc_name)) + .collect(); + + match self.one_bound_for_assoc_type(candidates, + "Self", + &assoc_name.as_str(), + span) { + Ok(bound) => bound, + Err(ErrorReported) => return (tcx.types.err, ty_path_def), + } + } + (&ty::TyParam(_), Def::SelfTy(Some(trait_did), None)) => { + let trait_node_id = tcx.map.as_local_node_id(trait_did).unwrap(); + match self.find_bound_for_assoc_item(trait_node_id, + keywords::SelfType.name(), + assoc_name, + span) { + Ok(bound) => bound, + Err(ErrorReported) => return (tcx.types.err, ty_path_def), + } + } + (&ty::TyParam(_), Def::TyParam(_, _, param_did, param_name)) => { + let param_node_id = tcx.map.as_local_node_id(param_did).unwrap(); + match self.find_bound_for_assoc_item(param_node_id, + param_name, + assoc_name, + span) { + Ok(bound) => bound, + Err(ErrorReported) => return (tcx.types.err, ty_path_def), + } + } + _ => { + self.report_ambiguous_associated_type(span, + &ty.to_string(), + "Trait", + &assoc_name.as_str()); + return (tcx.types.err, ty_path_def); + } + }; + + let trait_did = bound.0.def_id; + let ty = self.projected_ty_from_poly_trait_ref(span, bound, assoc_name); + + let item_did = if let Some(trait_id) = tcx.map.as_local_node_id(trait_did) { + // `ty::trait_items` used below requires information generated + // by type collection, which may be in progress at this point. + match tcx.map.expect_item(trait_id).node { + hir::ItemTrait(_, _, _, ref trait_items) => { + let item = trait_items.iter() + .find(|i| i.name == assoc_name) + .expect("missing associated type"); + tcx.map.local_def_id(item.id) + } + _ => bug!() + } + } else { + let trait_items = tcx.trait_items(trait_did); + let item = trait_items.iter().find(|i| i.name() == assoc_name); + item.expect("missing associated type").def_id() + }; + + (ty, Def::AssociatedTy(trait_did, item_did)) + } + + fn qpath_to_ty(&self, + rscope: &RegionScope, + span: Span, + param_mode: PathParamMode, + opt_self_ty: Option>, + trait_def_id: DefId, + trait_segment: &hir::PathSegment, + item_segment: &hir::PathSegment) + -> Ty<'tcx> + { + let tcx = self.tcx(); + + tcx.prohibit_type_params(slice::ref_slice(item_segment)); + + let self_ty = if let Some(ty) = opt_self_ty { + ty + } else { + let path_str = tcx.item_path_str(trait_def_id); + self.report_ambiguous_associated_type(span, + "Type", + &path_str, + &item_segment.identifier.name.as_str()); + return tcx.types.err; + }; + + debug!("qpath_to_ty: self_type={:?}", self_ty); + + let trait_ref = self.ast_path_to_mono_trait_ref(rscope, + span, + param_mode, + trait_def_id, + Some(self_ty), + trait_segment); + + debug!("qpath_to_ty: trait_ref={:?}", trait_ref); + + self.projected_ty(span, trait_ref, item_segment.identifier.name) + } + + /// Convert a type supplied as value for a type argument from AST into our + /// our internal representation. This is the same as `ast_ty_to_ty` but that + /// it applies the object lifetime default. + /// + /// # Parameters + /// + /// * `this`, `rscope`: the surrounding context + /// * `decl_generics`: the generics of the struct/enum/trait declaration being + /// referenced + /// * `index`: the index of the type parameter being instantiated from the list + /// (we assume it is in the `TypeSpace`) + /// * `region_substs`: a partial substitution consisting of + /// only the region type parameters being supplied to this type. + /// * `ast_ty`: the ast representation of the type being supplied + pub fn ast_ty_arg_to_ty(&self, + rscope: &RegionScope, + decl_generics: &ty::Generics<'tcx>, + index: usize, + region_substs: &Substs<'tcx>, + ast_ty: &hir::Ty) + -> Ty<'tcx> + { + let tcx = self.tcx(); + + if let Some(def) = decl_generics.types.opt_get(TypeSpace, index) { + let object_lifetime_default = def.object_lifetime_default.subst(tcx, region_substs); + let rscope1 = &ObjectLifetimeDefaultRscope::new(rscope, object_lifetime_default); + self.ast_ty_to_ty(rscope1, ast_ty) + } else { + self.ast_ty_to_ty(rscope, ast_ty) + } + } + + // Check the base def in a PathResolution and convert it to a Ty. If there are + // associated types in the PathResolution, these will need to be separately + // resolved. + fn base_def_to_ty(&self, + rscope: &RegionScope, + span: Span, + param_mode: PathParamMode, + def: &Def, + opt_self_ty: Option>, + base_segments: &[hir::PathSegment]) + -> Ty<'tcx> { + let tcx = self.tcx(); + + match *def { + Def::Trait(trait_def_id) => { + // N.B. this case overlaps somewhat with + // TyObjectSum, see that fn for details + let mut projection_bounds = Vec::new(); + + let trait_ref = + self.object_path_to_poly_trait_ref(rscope, + span, + param_mode, + trait_def_id, + base_segments.last().unwrap(), + &mut projection_bounds); + + tcx.prohibit_type_params(base_segments.split_last().unwrap().1); + self.trait_ref_to_object_type(rscope, + span, + trait_ref, + projection_bounds, + &[]) + } + Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) => { + tcx.prohibit_type_params(base_segments.split_last().unwrap().1); + self.ast_path_to_ty(rscope, + span, + param_mode, + did, + base_segments.last().unwrap()) + } + Def::TyParam(space, index, _, name) => { + tcx.prohibit_type_params(base_segments); + tcx.mk_param(space, index, name) + } + Def::SelfTy(_, Some(impl_id)) => { + // Self in impl (we know the concrete type). + tcx.prohibit_type_params(base_segments); + let ty = tcx.node_id_to_type(impl_id); + if let Some(free_substs) = self.get_free_substs() { + ty.subst(tcx, free_substs) + } else { + ty + } + } + Def::SelfTy(Some(_), None) => { + // Self in trait. + tcx.prohibit_type_params(base_segments); + tcx.mk_self_type() + } + Def::AssociatedTy(trait_did, _) => { + tcx.prohibit_type_params(&base_segments[..base_segments.len()-2]); + self.qpath_to_ty(rscope, + span, + param_mode, + opt_self_ty, + trait_did, + &base_segments[base_segments.len()-2], + base_segments.last().unwrap()) + } + Def::Mod(..) => { + // Used as sentinel by callers to indicate the `::A::B::C` form. + // FIXME(#22519) This part of the resolution logic should be + // avoided entirely for that form, once we stop needed a Def + // for `associated_path_def_to_ty`. + // Fixing this will also let use resolve ::Foo the same way we + // resolve Self::Foo, at the moment we can't resolve the former because + // we don't have the trait information around, which is just sad. + + assert!(base_segments.is_empty()); + + opt_self_ty.expect("missing T in ::a::b::c") + } + Def::PrimTy(prim_ty) => { + tcx.prim_ty_to_ty(base_segments, prim_ty) + } + Def::Err => { + self.set_tainted_by_errors(); + return self.tcx().types.err; + } + _ => { + span_err!(tcx.sess, span, E0248, + "found value `{}` used as a type", + tcx.item_path_str(def.def_id())); + return self.tcx().types.err; + } + } + } + + // Note that both base_segments and assoc_segments may be empty, although not at + // the same time. + pub fn finish_resolving_def_to_ty(&self, + rscope: &RegionScope, + span: Span, + param_mode: PathParamMode, + def: &Def, + opt_self_ty: Option>, + base_segments: &[hir::PathSegment], + assoc_segments: &[hir::PathSegment]) + -> Ty<'tcx> { + let mut ty = self.base_def_to_ty(rscope, + span, + param_mode, + def, + opt_self_ty, + base_segments); + let mut def = *def; + // If any associated type segments remain, attempt to resolve them. + for segment in assoc_segments { + if ty.sty == ty::TyError { + break; + } + // This is pretty bad (it will fail except for T::A and Self::A). + let (a_ty, a_def) = self.associated_path_def_to_ty(span, + ty, + def, + segment); + ty = a_ty; + def = a_def; + } + ty + } + + /// Parses the programmer's textual representation of a type into our + /// internal notion of a type. + pub fn ast_ty_to_ty(&self, rscope: &RegionScope, ast_ty: &hir::Ty) -> Ty<'tcx> { + debug!("ast_ty_to_ty(id={:?}, ast_ty={:?})", + ast_ty.id, ast_ty); + + let tcx = self.tcx(); + + match ast_ty.node { + hir::TyVec(ref ty) => { + tcx.mk_slice(self.ast_ty_to_ty(rscope, &ty)) + } + hir::TyObjectSum(ref ty, ref bounds) => { + match self.ast_ty_to_trait_ref(rscope, &ty, bounds) { + Ok((trait_ref, projection_bounds)) => { + self.trait_ref_to_object_type(rscope, + ast_ty.span, + trait_ref, + projection_bounds, + bounds) + } + Err(ErrorReported) => { + self.tcx().types.err + } + } + } + hir::TyPtr(ref mt) => { + tcx.mk_ptr(ty::TypeAndMut { + ty: self.ast_ty_to_ty(rscope, &mt.ty), + mutbl: mt.mutbl + }) + } + hir::TyRptr(ref region, ref mt) => { + let r = self.opt_ast_region_to_region(rscope, ast_ty.span, region); + debug!("TyRef r={:?}", r); + let rscope1 = + &ObjectLifetimeDefaultRscope::new( + rscope, + ty::ObjectLifetimeDefault::Specific(r)); + let t = self.ast_ty_to_ty(rscope1, &mt.ty); + tcx.mk_ref(tcx.mk_region(r), ty::TypeAndMut {ty: t, mutbl: mt.mutbl}) + } + hir::TyTup(ref fields) => { + let flds = fields.iter() + .map(|t| self.ast_ty_to_ty(rscope, &t)) + .collect(); + tcx.mk_tup(flds) + } + hir::TyBareFn(ref bf) => { + require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span); + tcx.mk_fn_ptr(self.ty_of_bare_fn(bf.unsafety, bf.abi, &bf.decl)) + } + hir::TyPolyTraitRef(ref bounds) => { + self.conv_ty_poly_trait_ref(rscope, ast_ty.span, bounds) + } + hir::TyPath(ref maybe_qself, ref path) => { + let path_res = if let Some(&d) = tcx.def_map.borrow().get(&ast_ty.id) { + d + } else if let Some(hir::QSelf { position: 0, .. }) = *maybe_qself { + // Create some fake resolution that can't possibly be a type. + def::PathResolution { + base_def: Def::Mod(tcx.map.local_def_id(ast::CRATE_NODE_ID)), + depth: path.segments.len() + } + } else { + span_bug!(ast_ty.span, "unbound path {:?}", ast_ty) + }; + let def = path_res.base_def; + let base_ty_end = path.segments.len() - path_res.depth; + let opt_self_ty = maybe_qself.as_ref().map(|qself| { + self.ast_ty_to_ty(rscope, &qself.ty) + }); + let ty = self.finish_resolving_def_to_ty(rscope, + ast_ty.span, + PathParamMode::Explicit, + &def, + opt_self_ty, + &path.segments[..base_ty_end], + &path.segments[base_ty_end..]); + + if path_res.depth != 0 && ty.sty != ty::TyError { + // Write back the new resolution. + tcx.def_map.borrow_mut().insert(ast_ty.id, def::PathResolution { + base_def: def, + depth: 0 + }); + } + + ty + } + hir::TyFixedLengthVec(ref ty, ref e) => { + let hint = UncheckedExprHint(tcx.types.usize); + match eval_const_expr_partial(tcx.global_tcx(), &e, hint, None) { + Ok(ConstVal::Integral(ConstInt::Usize(i))) => { + let i = i.as_u64(tcx.sess.target.uint_type); + assert_eq!(i as usize as u64, i); + tcx.mk_array(self.ast_ty_to_ty(rscope, &ty), i as usize) + }, + Ok(val) => { + span_err!(tcx.sess, ast_ty.span, E0249, + "expected usize value for array length, got {}", + val.description()); + self.tcx().types.err + }, + // array length errors happen before the global constant check + // so we need to report the real error + Err(ConstEvalErr { kind: ErroneousReferencedConstant(box r), ..}) | + Err(r) => { + let mut err = struct_span_err!(tcx.sess, r.span, E0250, + "array length constant \ + evaluation error: {}", + r.description()); + if !ast_ty.span.contains(r.span) { + span_note!(&mut err, ast_ty.span, "for array length here") + } + err.emit(); + self.tcx().types.err + } + } + } + hir::TyTypeof(ref _e) => { + span_err!(tcx.sess, ast_ty.span, E0516, + "`typeof` is a reserved keyword but unimplemented"); + tcx.types.err + } + hir::TyInfer => { + // TyInfer also appears as the type of arguments or return + // values in a ExprClosure, or as + // the type of local variables. Both of these cases are + // handled specially and will not descend into this routine. + self.ty_infer(None, None, None, ast_ty.span) + } + } + } + + pub fn ty_of_arg(&self, + rscope: &RegionScope, + a: &hir::Arg, + expected_ty: Option>) + -> Ty<'tcx> + { + match a.ty.node { + hir::TyInfer if expected_ty.is_some() => expected_ty.unwrap(), + hir::TyInfer => self.ty_infer(None, None, None, a.ty.span), + _ => self.ast_ty_to_ty(rscope, &a.ty), + } + } + + pub fn ty_of_method(&self, + sig: &hir::MethodSig, + untransformed_self_ty: Ty<'tcx>) + -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory) { + let self_info = Some(SelfInfo { + untransformed_self_ty: untransformed_self_ty, + explicit_self: &sig.explicit_self, + }); + let (bare_fn_ty, optional_explicit_self_category) = + self.ty_of_method_or_bare_fn(sig.unsafety, + sig.abi, + self_info, + &sig.decl); + (bare_fn_ty, optional_explicit_self_category.unwrap()) + } + + pub fn ty_of_bare_fn(&self, + unsafety: hir::Unsafety, abi: abi::Abi, + decl: &hir::FnDecl) + -> &'tcx ty::BareFnTy<'tcx> { + let (bare_fn_ty, _) = self.ty_of_method_or_bare_fn(unsafety, abi, None, decl); + bare_fn_ty + } + + fn ty_of_method_or_bare_fn<'a>(&self, + unsafety: hir::Unsafety, + abi: abi::Abi, + opt_self_info: Option>, + decl: &hir::FnDecl) + -> (&'tcx ty::BareFnTy<'tcx>, + Option) + { + debug!("ty_of_method_or_bare_fn"); + + // New region names that appear inside of the arguments of the function + // declaration are bound to that function type. + let rb = rscope::BindingRscope::new(); + + // `implied_output_region` is the region that will be assumed for any + // region parameters in the return type. In accordance with the rules for + // lifetime elision, we can determine it in two ways. First (determined + // here), if self is by-reference, then the implied output region is the + // region of the self parameter. + let (self_ty, explicit_self_category) = match opt_self_info { + None => (None, None), + Some(self_info) => self.determine_self_type(&rb, self_info) + }; + + // HACK(eddyb) replace the fake self type in the AST with the actual type. + let arg_params = if self_ty.is_some() { + &decl.inputs[1..] + } else { + &decl.inputs[..] + }; + let arg_tys: Vec = + arg_params.iter().map(|a| self.ty_of_arg(&rb, a, None)).collect(); + let arg_pats: Vec = + arg_params.iter().map(|a| pprust::pat_to_string(&a.pat)).collect(); + + // Second, if there was exactly one lifetime (either a substitution or a + // reference) in the arguments, then any anonymous regions in the output + // have that lifetime. + let implied_output_region = match explicit_self_category { + Some(ty::ExplicitSelfCategory::ByReference(region, _)) => Ok(region), + _ => self.find_implied_output_region(&arg_tys, arg_pats) + }; + + let output_ty = match decl.output { + hir::Return(ref output) => + ty::FnConverging(self.convert_ty_with_lifetime_elision(implied_output_region, + &output)), + hir::DefaultReturn(..) => ty::FnConverging(self.tcx().mk_nil()), + hir::NoReturn(..) => ty::FnDiverging + }; + + (self.tcx().mk_bare_fn(ty::BareFnTy { + unsafety: unsafety, + abi: abi, + sig: ty::Binder(ty::FnSig { + inputs: self_ty.into_iter().chain(arg_tys).collect(), + output: output_ty, + variadic: decl.variadic + }), + }), explicit_self_category) + } + + fn determine_self_type<'a>(&self, + rscope: &RegionScope, + self_info: SelfInfo<'a, 'tcx>) + -> (Option>, Option) + { + let self_ty = self_info.untransformed_self_ty; + return match self_info.explicit_self.node { + hir::SelfStatic => (None, Some(ty::ExplicitSelfCategory::Static)), + hir::SelfValue(_) => { + (Some(self_ty), Some(ty::ExplicitSelfCategory::ByValue)) + } + hir::SelfRegion(ref lifetime, mutability, _) => { + let region = + self.opt_ast_region_to_region(rscope, + self_info.explicit_self.span, + lifetime); + (Some(self.tcx().mk_ref( + self.tcx().mk_region(region), + ty::TypeAndMut { + ty: self_ty, + mutbl: mutability + })), + Some(ty::ExplicitSelfCategory::ByReference(region, mutability))) + } + hir::SelfExplicit(ref ast_type, _) => { + let explicit_type = self.ast_ty_to_ty(rscope, &ast_type); + + // We wish to (for now) categorize an explicit self + // declaration like `self: SomeType` into either `self`, + // `&self`, `&mut self`, or `Box`. We do this here + // by some simple pattern matching. A more precise check + // is done later in `check_method_self_type()`. + // + // Examples: + // + // ``` + // impl Foo for &T { + // // Legal declarations: + // fn method1(self: &&T); // ExplicitSelfCategory::ByReference + // fn method2(self: &T); // ExplicitSelfCategory::ByValue + // fn method3(self: Box<&T>); // ExplicitSelfCategory::ByBox + // + // // Invalid cases will be caught later by `check_method_self_type`: + // fn method_err1(self: &mut T); // ExplicitSelfCategory::ByReference + // } + // ``` + // + // To do the check we just count the number of "modifiers" + // on each type and compare them. If they are the same or + // the impl has more, we call it "by value". Otherwise, we + // look at the outermost modifier on the method decl and + // call it by-ref, by-box as appropriate. For method1, for + // example, the impl type has one modifier, but the method + // type has two, so we end up with + // ExplicitSelfCategory::ByReference. + + let impl_modifiers = count_modifiers(self_info.untransformed_self_ty); + let method_modifiers = count_modifiers(explicit_type); + + debug!("determine_explicit_self_category(self_info.untransformed_self_ty={:?} \ + explicit_type={:?} \ + modifiers=({},{})", + self_info.untransformed_self_ty, + explicit_type, + impl_modifiers, + method_modifiers); + + let category = if impl_modifiers >= method_modifiers { + ty::ExplicitSelfCategory::ByValue + } else { + match explicit_type.sty { + ty::TyRef(r, mt) => ty::ExplicitSelfCategory::ByReference(*r, mt.mutbl), + ty::TyBox(_) => ty::ExplicitSelfCategory::ByBox, + _ => ty::ExplicitSelfCategory::ByValue, + } + }; + + (Some(explicit_type), Some(category)) + } + }; + + fn count_modifiers(ty: Ty) -> usize { + match ty.sty { + ty::TyRef(_, mt) => count_modifiers(mt.ty) + 1, + ty::TyBox(t) => count_modifiers(t) + 1, + _ => 0, + } + } + } + + pub fn ty_of_closure(&self, + unsafety: hir::Unsafety, + decl: &hir::FnDecl, + abi: abi::Abi, + expected_sig: Option>) + -> ty::ClosureTy<'tcx> + { + debug!("ty_of_closure(expected_sig={:?})", + expected_sig); + + // new region names that appear inside of the fn decl are bound to + // that function type + let rb = rscope::BindingRscope::new(); + + let input_tys: Vec<_> = decl.inputs.iter().enumerate().map(|(i, a)| { + let expected_arg_ty = expected_sig.as_ref().and_then(|e| { + // no guarantee that the correct number of expected args + // were supplied + if i < e.inputs.len() { + Some(e.inputs[i]) + } else { + None + } + }); + self.ty_of_arg(&rb, a, expected_arg_ty) + }).collect(); + + let expected_ret_ty = expected_sig.map(|e| e.output); + + let is_infer = match decl.output { + hir::Return(ref output) if output.node == hir::TyInfer => true, + hir::DefaultReturn(..) => true, + _ => false + }; + + let output_ty = match decl.output { + _ if is_infer && expected_ret_ty.is_some() => + expected_ret_ty.unwrap(), + _ if is_infer => + ty::FnConverging(self.ty_infer(None, None, None, decl.output.span())), + hir::Return(ref output) => + ty::FnConverging(self.ast_ty_to_ty(&rb, &output)), + hir::DefaultReturn(..) => bug!(), + hir::NoReturn(..) => ty::FnDiverging + }; + + debug!("ty_of_closure: input_tys={:?}", input_tys); + debug!("ty_of_closure: output_ty={:?}", output_ty); + + ty::ClosureTy { + unsafety: unsafety, + abi: abi, + sig: ty::Binder(ty::FnSig {inputs: input_tys, + output: output_ty, + variadic: decl.variadic}), + } + } + + /// Given an existential type like `Foo+'a+Bar`, this routine converts + /// the `'a` and `Bar` intos an `ExistentialBounds` struct. + /// The `main_trait_refs` argument specifies the `Foo` -- it is absent + /// for closures. Eventually this should all be normalized, I think, + /// so that there is no "main trait ref" and instead we just have a flat + /// list of bounds as the existential type. + fn conv_existential_bounds(&self, + rscope: &RegionScope, + span: Span, + principal_trait_ref: ty::PolyTraitRef<'tcx>, + projection_bounds: Vec>, + ast_bounds: &[hir::TyParamBound]) + -> ty::ExistentialBounds<'tcx> + { + let partitioned_bounds = + partition_bounds(self.tcx(), span, ast_bounds); + + self.conv_existential_bounds_from_partitioned_bounds( + rscope, span, principal_trait_ref, projection_bounds, partitioned_bounds) + } + + fn conv_ty_poly_trait_ref(&self, + rscope: &RegionScope, + span: Span, + ast_bounds: &[hir::TyParamBound]) + -> Ty<'tcx> + { + let mut partitioned_bounds = partition_bounds(self.tcx(), span, &ast_bounds[..]); + + let mut projection_bounds = Vec::new(); + let main_trait_bound = if !partitioned_bounds.trait_bounds.is_empty() { + let trait_bound = partitioned_bounds.trait_bounds.remove(0); + self.instantiate_poly_trait_ref(rscope, + trait_bound, + None, + &mut projection_bounds) + } else { + span_err!(self.tcx().sess, span, E0224, + "at least one non-builtin trait is required for an object type"); + return self.tcx().types.err; + }; + + let bounds = + self.conv_existential_bounds_from_partitioned_bounds(rscope, + span, + main_trait_bound.clone(), + projection_bounds, + partitioned_bounds); + + self.make_object_type(span, main_trait_bound, bounds) + } + + pub fn conv_existential_bounds_from_partitioned_bounds(&self, + rscope: &RegionScope, + span: Span, + principal_trait_ref: ty::PolyTraitRef<'tcx>, + projection_bounds: Vec>, // Empty for boxed closures + partitioned_bounds: PartitionedBounds) + -> ty::ExistentialBounds<'tcx> + { + let PartitionedBounds { builtin_bounds, + trait_bounds, + region_bounds } = + partitioned_bounds; + + if !trait_bounds.is_empty() { + let b = &trait_bounds[0]; + span_err!(self.tcx().sess, b.trait_ref.path.span, E0225, + "only the builtin traits can be used as closure or object bounds"); + } + + let region_bound = + self.compute_object_lifetime_bound(span, + ®ion_bounds, + principal_trait_ref, + builtin_bounds); + + let region_bound = match region_bound { + Some(r) => r, + None => { + match rscope.object_lifetime_default(span) { + Some(r) => r, + None => { + span_err!(self.tcx().sess, span, E0228, + "the lifetime bound for this object type cannot be deduced \ + from context; please supply an explicit bound"); + ty::ReStatic + } + } + } + }; + + debug!("region_bound: {:?}", region_bound); + + ty::ExistentialBounds::new(region_bound, builtin_bounds, projection_bounds) + } + + /// Given the bounds on an object, determines what single region bound (if any) we can + /// use to summarize this type. The basic idea is that we will use the bound the user + /// provided, if they provided one, and otherwise search the supertypes of trait bounds + /// for region bounds. It may be that we can derive no bound at all, in which case + /// we return `None`. + fn compute_object_lifetime_bound(&self, + span: Span, + explicit_region_bounds: &[&hir::Lifetime], + principal_trait_ref: ty::PolyTraitRef<'tcx>, + builtin_bounds: ty::BuiltinBounds) + -> Option // if None, use the default + { + let tcx = self.tcx(); + + debug!("compute_opt_region_bound(explicit_region_bounds={:?}, \ + principal_trait_ref={:?}, builtin_bounds={:?})", + explicit_region_bounds, + principal_trait_ref, + builtin_bounds); + + if explicit_region_bounds.len() > 1 { + span_err!(tcx.sess, explicit_region_bounds[1].span, E0226, + "only a single explicit lifetime bound is permitted"); + } + + if !explicit_region_bounds.is_empty() { + // Explicitly specified region bound. Use that. + let r = explicit_region_bounds[0]; + return Some(ast_region_to_region(tcx, r)); + } + + if let Err(ErrorReported) = + self.ensure_super_predicates(span, principal_trait_ref.def_id()) { + return Some(ty::ReStatic); + } + + // No explicit region bound specified. Therefore, examine trait + // bounds and see if we can derive region bounds from those. + let derived_region_bounds = + object_region_bounds(tcx, &principal_trait_ref, builtin_bounds); + + // If there are no derived region bounds, then report back that we + // can find no region bound. The caller will use the default. + if derived_region_bounds.is_empty() { + return None; + } + + // If any of the derived region bounds are 'static, that is always + // the best choice. + if derived_region_bounds.iter().any(|r| ty::ReStatic == *r) { + return Some(ty::ReStatic); + } + + // Determine whether there is exactly one unique region in the set + // of derived region bounds. If so, use that. Otherwise, report an + // error. + let r = derived_region_bounds[0]; + if derived_region_bounds[1..].iter().any(|r1| r != *r1) { + span_err!(tcx.sess, span, E0227, + "ambiguous lifetime bound, explicit lifetime bound required"); + } + return Some(r); } - return Some(r); -} } pub struct PartitionedBounds<'a> { diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 899e4f62cc3..d55ca803c64 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -56,765 +56,767 @@ fn bad_struct_kind_err(sess: &Session, pat: &hir::Pat, path: &hir::Path, lint: b } impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> { -pub fn check_pat(&self, pat: &'gcx hir::Pat, expected: Ty<'tcx>) { - let tcx = self.tcx; + pub fn check_pat(&self, pat: &'gcx hir::Pat, expected: Ty<'tcx>) { + let tcx = self.tcx; - debug!("check_pat(pat={:?},expected={:?})", pat, expected); + debug!("check_pat(pat={:?},expected={:?})", pat, expected); - match pat.node { - PatKind::Wild => { - self.write_ty(pat.id, expected); - } - PatKind::Lit(ref lt) => { - self.check_expr(<); - let expr_ty = self.expr_ty(<); + match pat.node { + PatKind::Wild => { + self.write_ty(pat.id, expected); + } + PatKind::Lit(ref lt) => { + self.check_expr(<); + let expr_ty = self.expr_ty(<); - // Byte string patterns behave the same way as array patterns - // They can denote both statically and dynamically sized byte arrays - let mut pat_ty = expr_ty; - if let hir::ExprLit(ref lt) = lt.node { - if let ast::LitKind::ByteStr(_) = lt.node { - let expected_ty = self.structurally_resolved_type(pat.span, expected); - if let ty::TyRef(_, mt) = expected_ty.sty { - if let ty::TySlice(_) = mt.ty.sty { - pat_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), - tcx.mk_slice(tcx.types.u8)) + // Byte string patterns behave the same way as array patterns + // They can denote both statically and dynamically sized byte arrays + let mut pat_ty = expr_ty; + if let hir::ExprLit(ref lt) = lt.node { + if let ast::LitKind::ByteStr(_) = lt.node { + let expected_ty = self.structurally_resolved_type(pat.span, expected); + if let ty::TyRef(_, mt) = expected_ty.sty { + if let ty::TySlice(_) = mt.ty.sty { + pat_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), + tcx.mk_slice(tcx.types.u8)) + } } } } + + self.write_ty(pat.id, pat_ty); + + // somewhat surprising: in this case, the subtyping + // relation goes the opposite way as the other + // cases. Actually what we really want is not a subtyping + // relation at all but rather that there exists a LUB (so + // that they can be compared). However, in practice, + // constants are always scalars or strings. For scalars + // subtyping is irrelevant, and for strings `expr_ty` is + // type is `&'static str`, so if we say that + // + // &'static str <: expected + // + // that's equivalent to there existing a LUB. + self.demand_suptype(pat.span, expected, pat_ty); } + PatKind::Range(ref begin, ref end) => { + self.check_expr(begin); + self.check_expr(end); - self.write_ty(pat.id, pat_ty); + let lhs_ty = self.expr_ty(begin); + let rhs_ty = self.expr_ty(end); - // somewhat surprising: in this case, the subtyping - // relation goes the opposite way as the other - // cases. Actually what we really want is not a subtyping - // relation at all but rather that there exists a LUB (so - // that they can be compared). However, in practice, - // constants are always scalars or strings. For scalars - // subtyping is irrelevant, and for strings `expr_ty` is - // type is `&'static str`, so if we say that - // - // &'static str <: expected - // - // that's equivalent to there existing a LUB. - self.demand_suptype(pat.span, expected, pat_ty); - } - PatKind::Range(ref begin, ref end) => { - self.check_expr(begin); - self.check_expr(end); + // Check that both end-points are of numeric or char type. + let numeric_or_char = |ty: Ty| ty.is_numeric() || ty.is_char(); + let lhs_compat = numeric_or_char(lhs_ty); + let rhs_compat = numeric_or_char(rhs_ty); - let lhs_ty = self.expr_ty(begin); - let rhs_ty = self.expr_ty(end); + if !lhs_compat || !rhs_compat { + let span = if !lhs_compat && !rhs_compat { + pat.span + } else if !lhs_compat { + begin.span + } else { + end.span + }; - // Check that both end-points are of numeric or char type. - let numeric_or_char = |ty: Ty| ty.is_numeric() || ty.is_char(); - let lhs_compat = numeric_or_char(lhs_ty); - let rhs_compat = numeric_or_char(rhs_ty); - - if !lhs_compat || !rhs_compat { - let span = if !lhs_compat && !rhs_compat { - pat.span - } else if !lhs_compat { - begin.span - } else { - end.span - }; - - // Note: spacing here is intentional, we want a space before "start" and "end". - span_err!(tcx.sess, span, E0029, - "only char and numeric types are allowed in range patterns\n \ - start type: {}\n end type: {}", - self.ty_to_string(lhs_ty), - self.ty_to_string(rhs_ty) - ); - return; - } - - // Check that the types of the end-points can be unified. - let types_unify = self.require_same_types(pat.span, rhs_ty, lhs_ty, - "mismatched types in range"); - - // It's ok to return without a message as `require_same_types` prints an error. - if !types_unify { - return; - } - - // Now that we know the types can be unified we find the unified type and use - // it to type the entire expression. - let common_type = self.resolve_type_vars_if_possible(&lhs_ty); - - self.write_ty(pat.id, common_type); - - // subtyping doesn't matter here, as the value is some kind of scalar - self.demand_eqtype(pat.span, expected, lhs_ty); - } - PatKind::Path(..) | PatKind::Ident(..) - if pat_is_resolved_const(&tcx.def_map.borrow(), pat) => { - if let Some(pat_def) = tcx.def_map.borrow().get(&pat.id) { - let const_did = pat_def.def_id(); - let const_scheme = tcx.lookup_item_type(const_did); - assert!(const_scheme.generics.is_empty()); - let const_ty = self.instantiate_type_scheme(pat.span, - &Substs::empty(), - &const_scheme.ty); - self.write_ty(pat.id, const_ty); - - // FIXME(#20489) -- we should limit the types here to scalars or something! - - // As with PatKind::Lit, what we really want here is that there - // exist a LUB, but for the cases that can occur, subtype - // is good enough. - self.demand_suptype(pat.span, expected, const_ty); - } else { - self.write_error(pat.id); - } - } - PatKind::Ident(bm, ref path, ref sub) if pat_is_binding(&tcx.def_map.borrow(), pat) => { - let typ = self.local_ty(pat.span, pat.id); - match bm { - hir::BindByRef(mutbl) => { - // if the binding is like - // ref x | ref const x | ref mut x - // then `x` is assigned a value of type `&M T` where M is the mutability - // and T is the expected type. - let region_var = self.next_region_var(infer::PatternRegion(pat.span)); - let mt = ty::TypeAndMut { ty: expected, mutbl: mutbl }; - let region_ty = tcx.mk_ref(tcx.mk_region(region_var), mt); - - // `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` is - // required. However, we use equality, which is stronger. See (*) for - // an explanation. - self.demand_eqtype(pat.span, region_ty, typ); - } - // otherwise the type of x is the expected type T - hir::BindByValue(_) => { - // As above, `T <: typeof(x)` is required but we - // use equality, see (*) below. - self.demand_eqtype(pat.span, expected, typ); - } - } - - self.write_ty(pat.id, typ); - - // if there are multiple arms, make sure they all agree on - // what the type of the binding `x` ought to be - if let Some(&canon_id) = self.map.get(&path.node.name) { - if canon_id != pat.id { - let ct = self.local_ty(pat.span, canon_id); - self.demand_eqtype(pat.span, ct, typ); - } - - if let Some(ref p) = *sub { - self.check_pat(&p, expected); - } - } - } - PatKind::Ident(_, ref path, _) => { - let path = hir::Path::from_ident(path.span, path.node); - self.check_pat_enum(pat, &path, Some(&[]), expected, false); - } - PatKind::TupleStruct(ref path, ref subpats) => { - self.check_pat_enum(pat, path, subpats.as_ref().map(|v| &v[..]), expected, true); - } - PatKind::Path(ref path) => { - self.check_pat_enum(pat, path, Some(&[]), expected, false); - } - PatKind::QPath(ref qself, ref path) => { - let self_ty = self.to_ty(&qself.ty); - let path_res = if let Some(&d) = tcx.def_map.borrow().get(&pat.id) { - if d.base_def == Def::Err { - self.set_tainted_by_errors(); - self.write_error(pat.id); + // Note: spacing here is intentional, we want a space before "start" and "end". + span_err!(tcx.sess, span, E0029, + "only char and numeric types are allowed in range patterns\n \ + start type: {}\n end type: {}", + self.ty_to_string(lhs_ty), + self.ty_to_string(rhs_ty) + ); return; } - d - } else if qself.position == 0 { - // This is just a sentinel for finish_resolving_def_to_ty. - let sentinel = self.tcx.map.local_def_id(ast::CRATE_NODE_ID); - def::PathResolution { - base_def: Def::Mod(sentinel), - depth: path.segments.len() + + // Check that the types of the end-points can be unified. + let types_unify = self.require_same_types(pat.span, rhs_ty, lhs_ty, + "mismatched types in range"); + + // It's ok to return without a message as `require_same_types` prints an error. + if !types_unify { + return; } - } else { - debug!("unbound path {:?}", pat); - self.write_error(pat.id); - return; - }; - if let Some((opt_ty, segments, def)) = - self.resolve_ty_and_def_ufcs(path_res, Some(self_ty), - path, pat.span, pat.id) { - if self.check_assoc_item_is_const(def, pat.span) { - let scheme = tcx.lookup_item_type(def.def_id()); - let predicates = tcx.lookup_predicates(def.def_id()); - self.instantiate_path(segments, scheme, &predicates, - opt_ty, def, pat.span, pat.id); - let const_ty = self.node_ty(pat.id); + + // Now that we know the types can be unified we find the unified type and use + // it to type the entire expression. + let common_type = self.resolve_type_vars_if_possible(&lhs_ty); + + self.write_ty(pat.id, common_type); + + // subtyping doesn't matter here, as the value is some kind of scalar + self.demand_eqtype(pat.span, expected, lhs_ty); + } + PatKind::Path(..) | PatKind::Ident(..) + if pat_is_resolved_const(&tcx.def_map.borrow(), pat) => { + if let Some(pat_def) = tcx.def_map.borrow().get(&pat.id) { + let const_did = pat_def.def_id(); + let const_scheme = tcx.lookup_item_type(const_did); + assert!(const_scheme.generics.is_empty()); + let const_ty = self.instantiate_type_scheme(pat.span, + &Substs::empty(), + &const_scheme.ty); + self.write_ty(pat.id, const_ty); + + // FIXME(#20489) -- we should limit the types here to scalars or something! + + // As with PatKind::Lit, what we really want here is that there + // exist a LUB, but for the cases that can occur, subtype + // is good enough. self.demand_suptype(pat.span, expected, const_ty); } else { - self.write_error(pat.id) + self.write_error(pat.id); } } - } - PatKind::Struct(ref path, ref fields, etc) => { - self.check_pat_struct(pat, path, fields, etc, expected); - } - PatKind::Tup(ref elements) => { - let element_tys: Vec<_> = - (0..elements.len()).map(|_| self.next_ty_var()).collect(); - let pat_ty = tcx.mk_tup(element_tys.clone()); - self.write_ty(pat.id, pat_ty); - self.demand_eqtype(pat.span, expected, pat_ty); - for (element_pat, element_ty) in elements.iter().zip(element_tys) { - self.check_pat(&element_pat, element_ty); - } - } - PatKind::Box(ref inner) => { - let inner_ty = self.next_ty_var(); - let uniq_ty = tcx.mk_box(inner_ty); + PatKind::Ident(bm, ref path, ref sub) + if pat_is_binding(&tcx.def_map.borrow(), pat) => { + let typ = self.local_ty(pat.span, pat.id); + match bm { + hir::BindByRef(mutbl) => { + // if the binding is like + // ref x | ref const x | ref mut x + // then `x` is assigned a value of type `&M T` where M is the mutability + // and T is the expected type. + let region_var = self.next_region_var(infer::PatternRegion(pat.span)); + let mt = ty::TypeAndMut { ty: expected, mutbl: mutbl }; + let region_ty = tcx.mk_ref(tcx.mk_region(region_var), mt); - if self.check_dereferencable(pat.span, expected, &inner) { - // Here, `demand::subtype` is good enough, but I don't - // think any errors can be introduced by using - // `demand::eqtype`. - self.demand_eqtype(pat.span, expected, uniq_ty); - self.write_ty(pat.id, uniq_ty); - self.check_pat(&inner, inner_ty); - } else { - self.write_error(pat.id); - self.check_pat(&inner, tcx.types.err); + // `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` is + // required. However, we use equality, which is stronger. See (*) for + // an explanation. + self.demand_eqtype(pat.span, region_ty, typ); + } + // otherwise the type of x is the expected type T + hir::BindByValue(_) => { + // As above, `T <: typeof(x)` is required but we + // use equality, see (*) below. + self.demand_eqtype(pat.span, expected, typ); + } + } + + self.write_ty(pat.id, typ); + + // if there are multiple arms, make sure they all agree on + // what the type of the binding `x` ought to be + if let Some(&canon_id) = self.map.get(&path.node.name) { + if canon_id != pat.id { + let ct = self.local_ty(pat.span, canon_id); + self.demand_eqtype(pat.span, ct, typ); + } + + if let Some(ref p) = *sub { + self.check_pat(&p, expected); + } + } } - } - PatKind::Ref(ref inner, mutbl) => { - let expected = self.shallow_resolve(expected); - if self.check_dereferencable(pat.span, expected, &inner) { + PatKind::Ident(_, ref path, _) => { + let path = hir::Path::from_ident(path.span, path.node); + self.check_pat_enum(pat, &path, Some(&[]), expected, false); + } + PatKind::TupleStruct(ref path, ref subpats) => { + self.check_pat_enum(pat, path, subpats.as_ref().map(|v| &v[..]), expected, true); + } + PatKind::Path(ref path) => { + self.check_pat_enum(pat, path, Some(&[]), expected, false); + } + PatKind::QPath(ref qself, ref path) => { + let self_ty = self.to_ty(&qself.ty); + let path_res = if let Some(&d) = tcx.def_map.borrow().get(&pat.id) { + if d.base_def == Def::Err { + self.set_tainted_by_errors(); + self.write_error(pat.id); + return; + } + d + } else if qself.position == 0 { + // This is just a sentinel for finish_resolving_def_to_ty. + let sentinel = self.tcx.map.local_def_id(ast::CRATE_NODE_ID); + def::PathResolution { + base_def: Def::Mod(sentinel), + depth: path.segments.len() + } + } else { + debug!("unbound path {:?}", pat); + self.write_error(pat.id); + return; + }; + if let Some((opt_ty, segments, def)) = + self.resolve_ty_and_def_ufcs(path_res, Some(self_ty), + path, pat.span, pat.id) { + if self.check_assoc_item_is_const(def, pat.span) { + let scheme = tcx.lookup_item_type(def.def_id()); + let predicates = tcx.lookup_predicates(def.def_id()); + self.instantiate_path(segments, scheme, &predicates, + opt_ty, def, pat.span, pat.id); + let const_ty = self.node_ty(pat.id); + self.demand_suptype(pat.span, expected, const_ty); + } else { + self.write_error(pat.id) + } + } + } + PatKind::Struct(ref path, ref fields, etc) => { + self.check_pat_struct(pat, path, fields, etc, expected); + } + PatKind::Tup(ref elements) => { + let element_tys: Vec<_> = + (0..elements.len()).map(|_| self.next_ty_var()).collect(); + let pat_ty = tcx.mk_tup(element_tys.clone()); + self.write_ty(pat.id, pat_ty); + self.demand_eqtype(pat.span, expected, pat_ty); + for (element_pat, element_ty) in elements.iter().zip(element_tys) { + self.check_pat(&element_pat, element_ty); + } + } + PatKind::Box(ref inner) => { + let inner_ty = self.next_ty_var(); + let uniq_ty = tcx.mk_box(inner_ty); + + if self.check_dereferencable(pat.span, expected, &inner) { + // Here, `demand::subtype` is good enough, but I don't + // think any errors can be introduced by using + // `demand::eqtype`. + self.demand_eqtype(pat.span, expected, uniq_ty); + self.write_ty(pat.id, uniq_ty); + self.check_pat(&inner, inner_ty); + } else { + self.write_error(pat.id); + self.check_pat(&inner, tcx.types.err); + } + } + PatKind::Ref(ref inner, mutbl) => { + let expected = self.shallow_resolve(expected); + if self.check_dereferencable(pat.span, expected, &inner) { + // `demand::subtype` would be good enough, but using + // `eqtype` turns out to be equally general. See (*) + // below for details. + + // Take region, inner-type from expected type if we + // can, to avoid creating needless variables. This + // also helps with the bad interactions of the given + // hack detailed in (*) below. + let (rptr_ty, inner_ty) = match expected.sty { + ty::TyRef(_, mt) if mt.mutbl == mutbl => { + (expected, mt.ty) + } + _ => { + let inner_ty = self.next_ty_var(); + let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl }; + let region = self.next_region_var(infer::PatternRegion(pat.span)); + let rptr_ty = tcx.mk_ref(tcx.mk_region(region), mt); + self.demand_eqtype(pat.span, expected, rptr_ty); + (rptr_ty, inner_ty) + } + }; + + self.write_ty(pat.id, rptr_ty); + self.check_pat(&inner, inner_ty); + } else { + self.write_error(pat.id); + self.check_pat(&inner, tcx.types.err); + } + } + PatKind::Vec(ref before, ref slice, ref after) => { + let expected_ty = self.structurally_resolved_type(pat.span, expected); + let inner_ty = self.next_ty_var(); + let pat_ty = match expected_ty.sty { + ty::TyArray(_, size) => tcx.mk_array(inner_ty, { + let min_len = before.len() + after.len(); + match *slice { + Some(_) => cmp::max(min_len, size), + None => min_len + } + }), + _ => { + let region = self.next_region_var(infer::PatternRegion(pat.span)); + tcx.mk_ref(tcx.mk_region(region), ty::TypeAndMut { + ty: tcx.mk_slice(inner_ty), + mutbl: expected_ty.builtin_deref(true, ty::NoPreference) + .map_or(hir::MutImmutable, |mt| mt.mutbl) + }) + } + }; + + self.write_ty(pat.id, pat_ty); + // `demand::subtype` would be good enough, but using // `eqtype` turns out to be equally general. See (*) // below for details. + self.demand_eqtype(pat.span, expected, pat_ty); - // Take region, inner-type from expected type if we - // can, to avoid creating needless variables. This - // also helps with the bad interactions of the given - // hack detailed in (*) below. - let (rptr_ty, inner_ty) = match expected.sty { - ty::TyRef(_, mt) if mt.mutbl == mutbl => { - (expected, mt.ty) - } - _ => { - let inner_ty = self.next_ty_var(); - let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl }; - let region = self.next_region_var(infer::PatternRegion(pat.span)); - let rptr_ty = tcx.mk_ref(tcx.mk_region(region), mt); - self.demand_eqtype(pat.span, expected, rptr_ty); - (rptr_ty, inner_ty) - } - }; - - self.write_ty(pat.id, rptr_ty); - self.check_pat(&inner, inner_ty); - } else { - self.write_error(pat.id); - self.check_pat(&inner, tcx.types.err); - } - } - PatKind::Vec(ref before, ref slice, ref after) => { - let expected_ty = self.structurally_resolved_type(pat.span, expected); - let inner_ty = self.next_ty_var(); - let pat_ty = match expected_ty.sty { - ty::TyArray(_, size) => tcx.mk_array(inner_ty, { - let min_len = before.len() + after.len(); - match *slice { - Some(_) => cmp::max(min_len, size), - None => min_len - } - }), - _ => { - let region = self.next_region_var(infer::PatternRegion(pat.span)); - tcx.mk_ref(tcx.mk_region(region), ty::TypeAndMut { - ty: tcx.mk_slice(inner_ty), - mutbl: expected_ty.builtin_deref(true, ty::NoPreference).map(|mt| mt.mutbl) - .unwrap_or(hir::MutImmutable) - }) + for elt in before { + self.check_pat(&elt, inner_ty); } - }; + if let Some(ref slice) = *slice { + let region = self.next_region_var(infer::PatternRegion(pat.span)); + let mutbl = expected_ty.builtin_deref(true, ty::NoPreference) + .map_or(hir::MutImmutable, |mt| mt.mutbl); - self.write_ty(pat.id, pat_ty); - - // `demand::subtype` would be good enough, but using - // `eqtype` turns out to be equally general. See (*) - // below for details. - self.demand_eqtype(pat.span, expected, pat_ty); - - for elt in before { - self.check_pat(&elt, inner_ty); - } - if let Some(ref slice) = *slice { - let region = self.next_region_var(infer::PatternRegion(pat.span)); - let mutbl = expected_ty.builtin_deref(true, ty::NoPreference) - .map_or(hir::MutImmutable, |mt| mt.mutbl); - - let slice_ty = tcx.mk_ref(tcx.mk_region(region), ty::TypeAndMut { - ty: tcx.mk_slice(inner_ty), - mutbl: mutbl - }); - self.check_pat(&slice, slice_ty); - } - for elt in after { - self.check_pat(&elt, inner_ty); + let slice_ty = tcx.mk_ref(tcx.mk_region(region), ty::TypeAndMut { + ty: tcx.mk_slice(inner_ty), + mutbl: mutbl + }); + self.check_pat(&slice, slice_ty); + } + for elt in after { + self.check_pat(&elt, inner_ty); + } } } + + + // (*) In most of the cases above (literals and constants being + // the exception), we relate types using strict equality, evewn + // though subtyping would be sufficient. There are a few reasons + // for this, some of which are fairly subtle and which cost me + // (nmatsakis) an hour or two debugging to remember, so I thought + // I'd write them down this time. + // + // 1. There is no loss of expressiveness here, though it does + // cause some inconvenience. What we are saying is that the type + // of `x` becomes *exactly* what is expected. This can cause unnecessary + // errors in some cases, such as this one: + // it will cause errors in a case like this: + // + // ``` + // fn foo<'x>(x: &'x int) { + // let a = 1; + // let mut z = x; + // z = &a; + // } + // ``` + // + // The reason we might get an error is that `z` might be + // assigned a type like `&'x int`, and then we would have + // a problem when we try to assign `&a` to `z`, because + // the lifetime of `&a` (i.e., the enclosing block) is + // shorter than `'x`. + // + // HOWEVER, this code works fine. The reason is that the + // expected type here is whatever type the user wrote, not + // the initializer's type. In this case the user wrote + // nothing, so we are going to create a type variable `Z`. + // Then we will assign the type of the initializer (`&'x + // int`) as a subtype of `Z`: `&'x int <: Z`. And hence we + // will instantiate `Z` as a type `&'0 int` where `'0` is + // a fresh region variable, with the constraint that `'x : + // '0`. So basically we're all set. + // + // Note that there are two tests to check that this remains true + // (`regions-reassign-{match,let}-bound-pointer.rs`). + // + // 2. Things go horribly wrong if we use subtype. The reason for + // THIS is a fairly subtle case involving bound regions. See the + // `givens` field in `region_inference`, as well as the test + // `regions-relate-bound-regions-on-closures-to-inference-variables.rs`, + // for details. Short version is that we must sometimes detect + // relationships between specific region variables and regions + // bound in a closure signature, and that detection gets thrown + // off when we substitute fresh region variables here to enable + // subtyping. } - - // (*) In most of the cases above (literals and constants being - // the exception), we relate types using strict equality, evewn - // though subtyping would be sufficient. There are a few reasons - // for this, some of which are fairly subtle and which cost me - // (nmatsakis) an hour or two debugging to remember, so I thought - // I'd write them down this time. - // - // 1. There is no loss of expressiveness here, though it does - // cause some inconvenience. What we are saying is that the type - // of `x` becomes *exactly* what is expected. This can cause unnecessary - // errors in some cases, such as this one: - // it will cause errors in a case like this: - // - // ``` - // fn foo<'x>(x: &'x int) { - // let a = 1; - // let mut z = x; - // z = &a; - // } - // ``` - // - // The reason we might get an error is that `z` might be - // assigned a type like `&'x int`, and then we would have - // a problem when we try to assign `&a` to `z`, because - // the lifetime of `&a` (i.e., the enclosing block) is - // shorter than `'x`. - // - // HOWEVER, this code works fine. The reason is that the - // expected type here is whatever type the user wrote, not - // the initializer's type. In this case the user wrote - // nothing, so we are going to create a type variable `Z`. - // Then we will assign the type of the initializer (`&'x - // int`) as a subtype of `Z`: `&'x int <: Z`. And hence we - // will instantiate `Z` as a type `&'0 int` where `'0` is - // a fresh region variable, with the constraint that `'x : - // '0`. So basically we're all set. - // - // Note that there are two tests to check that this remains true - // (`regions-reassign-{match,let}-bound-pointer.rs`). - // - // 2. Things go horribly wrong if we use subtype. The reason for - // THIS is a fairly subtle case involving bound regions. See the - // `givens` field in `region_inference`, as well as the test - // `regions-relate-bound-regions-on-closures-to-inference-variables.rs`, - // for details. Short version is that we must sometimes detect - // relationships between specific region variables and regions - // bound in a closure signature, and that detection gets thrown - // off when we substitute fresh region variables here to enable - // subtyping. -} - -fn check_assoc_item_is_const(&self, def: Def, span: Span) -> bool { - match def { - Def::AssociatedConst(..) => true, - Def::Method(..) => { - span_err!(self.tcx.sess, span, E0327, - "associated items in match patterns must be constants"); - false - } - _ => { - span_bug!(span, "non-associated item in check_assoc_item_is_const"); - } - } -} - -pub fn check_dereferencable(&self, span: Span, expected: Ty<'tcx>, inner: &hir::Pat) -> bool { - let tcx = self.tcx; - if pat_is_binding(&tcx.def_map.borrow(), inner) { - let expected = self.shallow_resolve(expected); - expected.builtin_deref(true, ty::NoPreference).map_or(true, |mt| match mt.ty.sty { - ty::TyTrait(_) => { - // This is "x = SomeTrait" being reduced from - // "let &x = &SomeTrait" or "let box x = Box", an error. - span_err!(tcx.sess, span, E0033, - "type `{}` cannot be dereferenced", - self.ty_to_string(expected)); + fn check_assoc_item_is_const(&self, def: Def, span: Span) -> bool { + match def { + Def::AssociatedConst(..) => true, + Def::Method(..) => { + span_err!(self.tcx.sess, span, E0327, + "associated items in match patterns must be constants"); false } - _ => true - }) - } else { - true + _ => { + span_bug!(span, "non-associated item in check_assoc_item_is_const"); + } + } + } + + pub fn check_dereferencable(&self, span: Span, expected: Ty<'tcx>, inner: &hir::Pat) -> bool { + let tcx = self.tcx; + if pat_is_binding(&tcx.def_map.borrow(), inner) { + let expected = self.shallow_resolve(expected); + expected.builtin_deref(true, ty::NoPreference).map_or(true, |mt| match mt.ty.sty { + ty::TyTrait(_) => { + // This is "x = SomeTrait" being reduced from + // "let &x = &SomeTrait" or "let box x = Box", an error. + span_err!(tcx.sess, span, E0033, + "type `{}` cannot be dereferenced", + self.ty_to_string(expected)); + false + } + _ => true + }) + } else { + true + } } -} } impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { -pub fn check_match(&self, - expr: &'gcx hir::Expr, - discrim: &'gcx hir::Expr, - arms: &'gcx [hir::Arm], - expected: Expectation<'tcx>, - match_src: hir::MatchSource) { - let tcx = self.tcx; + pub fn check_match(&self, + expr: &'gcx hir::Expr, + discrim: &'gcx hir::Expr, + arms: &'gcx [hir::Arm], + expected: Expectation<'tcx>, + match_src: hir::MatchSource) { + let tcx = self.tcx; - // Not entirely obvious: if matches may create ref bindings, we - // want to use the *precise* type of the discriminant, *not* some - // supertype, as the "discriminant type" (issue #23116). - let contains_ref_bindings = arms.iter() - .filter_map(|a| tcx.arm_contains_ref_binding(a)) - .max_by_key(|m| match *m { - hir::MutMutable => 1, - hir::MutImmutable => 0, - }); - let discrim_ty; - if let Some(m) = contains_ref_bindings { - self.check_expr_with_lvalue_pref(discrim, LvaluePreference::from_mutbl(m)); - discrim_ty = self.expr_ty(discrim); - } else { - // ...but otherwise we want to use any supertype of the - // discriminant. This is sort of a workaround, see note (*) in - // `check_pat` for some details. - discrim_ty = self.next_ty_var(); - self.check_expr_has_type(discrim, discrim_ty); - }; - - // Typecheck the patterns first, so that we get types for all the - // bindings. - for arm in arms { - let pcx = PatCtxt { - fcx: self, - map: pat_id_map(&tcx.def_map, &arm.pats[0]), - }; - for p in &arm.pats { - pcx.check_pat(&p, discrim_ty); - } - } - - // Now typecheck the blocks. - // - // The result of the match is the common supertype of all the - // arms. Start out the value as bottom, since it's the, well, - // bottom the type lattice, and we'll be moving up the lattice as - // we process each arm. (Note that any match with 0 arms is matching - // on any empty type and is therefore unreachable; should the flow - // of execution reach it, we will panic, so bottom is an appropriate - // type in that case) - let expected = expected.adjust_for_branches(self); - let mut result_ty = self.next_diverging_ty_var(); - let coerce_first = match expected { - // We don't coerce to `()` so that if the match expression is a - // statement it's branches can have any consistent type. That allows - // us to give better error messages (pointing to a usually better - // arm for inconsistent arms or to the whole match when a `()` type - // is required). - Expectation::ExpectHasType(ety) if ety != self.tcx.mk_nil() => { - ety - } - _ => result_ty - }; - for (i, arm) in arms.iter().enumerate() { - if let Some(ref e) = arm.guard { - self.check_expr_has_type(e, tcx.types.bool); - } - self.check_expr_with_expectation(&arm.body, expected); - let arm_ty = self.expr_ty(&arm.body); - - if result_ty.references_error() || arm_ty.references_error() { - result_ty = tcx.types.err; - continue; - } - - // Handle the fallback arm of a desugared if-let like a missing else. - let is_if_let_fallback = match match_src { - hir::MatchSource::IfLetDesugar { contains_else_clause: false } => { - i == arms.len() - 1 && arm_ty.is_nil() - } - _ => false - }; - - let origin = if is_if_let_fallback { - TypeOrigin::IfExpressionWithNoElse(expr.span) + // Not entirely obvious: if matches may create ref bindings, we + // want to use the *precise* type of the discriminant, *not* some + // supertype, as the "discriminant type" (issue #23116). + let contains_ref_bindings = arms.iter() + .filter_map(|a| tcx.arm_contains_ref_binding(a)) + .max_by_key(|m| match *m { + hir::MutMutable => 1, + hir::MutImmutable => 0, + }); + let discrim_ty; + if let Some(m) = contains_ref_bindings { + self.check_expr_with_lvalue_pref(discrim, LvaluePreference::from_mutbl(m)); + discrim_ty = self.expr_ty(discrim); } else { - TypeOrigin::MatchExpressionArm(expr.span, arm.body.span, match_src) + // ...but otherwise we want to use any supertype of the + // discriminant. This is sort of a workaround, see note (*) in + // `check_pat` for some details. + discrim_ty = self.next_ty_var(); + self.check_expr_has_type(discrim, discrim_ty); }; - let result = if is_if_let_fallback { - self.eq_types(true, origin, arm_ty, result_ty) - .map(|InferOk { obligations, .. }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - arm_ty - }) - } else if i == 0 { - // Special-case the first arm, as it has no "previous expressions". - self.try_coerce(&arm.body, coerce_first) - } else { - let prev_arms = || arms[..i].iter().map(|arm| &*arm.body); - self.try_find_coercion_lub(origin, prev_arms, result_ty, &arm.body) - }; - - result_ty = match result { - Ok(ty) => ty, - Err(e) => { - let (expected, found) = if is_if_let_fallback { - (arm_ty, result_ty) - } else { - (result_ty, arm_ty) - }; - self.report_mismatched_types(origin, expected, found, e); - self.tcx.types.err + // Typecheck the patterns first, so that we get types for all the + // bindings. + for arm in arms { + let pcx = PatCtxt { + fcx: self, + map: pat_id_map(&tcx.def_map, &arm.pats[0]), + }; + for p in &arm.pats { + pcx.check_pat(&p, discrim_ty); } - }; - } + } - self.write_ty(expr.id, result_ty); -} + // Now typecheck the blocks. + // + // The result of the match is the common supertype of all the + // arms. Start out the value as bottom, since it's the, well, + // bottom the type lattice, and we'll be moving up the lattice as + // we process each arm. (Note that any match with 0 arms is matching + // on any empty type and is therefore unreachable; should the flow + // of execution reach it, we will panic, so bottom is an appropriate + // type in that case) + let expected = expected.adjust_for_branches(self); + let mut result_ty = self.next_diverging_ty_var(); + let coerce_first = match expected { + // We don't coerce to `()` so that if the match expression is a + // statement it's branches can have any consistent type. That allows + // us to give better error messages (pointing to a usually better + // arm for inconsistent arms or to the whole match when a `()` type + // is required). + Expectation::ExpectHasType(ety) if ety != self.tcx.mk_nil() => { + ety + } + _ => result_ty + }; + for (i, arm) in arms.iter().enumerate() { + if let Some(ref e) = arm.guard { + self.check_expr_has_type(e, tcx.types.bool); + } + self.check_expr_with_expectation(&arm.body, expected); + let arm_ty = self.expr_ty(&arm.body); + + if result_ty.references_error() || arm_ty.references_error() { + result_ty = tcx.types.err; + continue; + } + + // Handle the fallback arm of a desugared if-let like a missing else. + let is_if_let_fallback = match match_src { + hir::MatchSource::IfLetDesugar { contains_else_clause: false } => { + i == arms.len() - 1 && arm_ty.is_nil() + } + _ => false + }; + + let origin = if is_if_let_fallback { + TypeOrigin::IfExpressionWithNoElse(expr.span) + } else { + TypeOrigin::MatchExpressionArm(expr.span, arm.body.span, match_src) + }; + + let result = if is_if_let_fallback { + self.eq_types(true, origin, arm_ty, result_ty) + .map(|InferOk { obligations, .. }| { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()); + arm_ty + }) + } else if i == 0 { + // Special-case the first arm, as it has no "previous expressions". + self.try_coerce(&arm.body, coerce_first) + } else { + let prev_arms = || arms[..i].iter().map(|arm| &*arm.body); + self.try_find_coercion_lub(origin, prev_arms, result_ty, &arm.body) + }; + + result_ty = match result { + Ok(ty) => ty, + Err(e) => { + let (expected, found) = if is_if_let_fallback { + (arm_ty, result_ty) + } else { + (result_ty, arm_ty) + }; + self.report_mismatched_types(origin, expected, found, e); + self.tcx.types.err + } + }; + } + + self.write_ty(expr.id, result_ty); + } } impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> { -pub fn check_pat_struct(&self, pat: &'gcx hir::Pat, - path: &hir::Path, fields: &'gcx [Spanned], - etc: bool, expected: Ty<'tcx>) { - let tcx = self.tcx; + pub fn check_pat_struct(&self, pat: &'gcx hir::Pat, + path: &hir::Path, fields: &'gcx [Spanned], + etc: bool, expected: Ty<'tcx>) { + let tcx = self.tcx; - let def = tcx.def_map.borrow().get(&pat.id).unwrap().full_def(); - let variant = match self.def_struct_variant(def, path.span) { - Some((_, variant)) => variant, - None => { - let name = pprust::path_to_string(path); - span_err!(tcx.sess, pat.span, E0163, - "`{}` does not name a struct or a struct variant", name); - self.write_error(pat.id); + let def = tcx.def_map.borrow().get(&pat.id).unwrap().full_def(); + let variant = match self.def_struct_variant(def, path.span) { + Some((_, variant)) => variant, + None => { + let name = pprust::path_to_string(path); + span_err!(tcx.sess, pat.span, E0163, + "`{}` does not name a struct or a struct variant", name); + self.write_error(pat.id); - for field in fields { - self.check_pat(&field.node.pat, tcx.types.err); + for field in fields { + self.check_pat(&field.node.pat, tcx.types.err); + } + return; } + }; + + let pat_ty = self.instantiate_type(def.def_id(), path); + let item_substs = match pat_ty.sty { + ty::TyStruct(_, substs) | ty::TyEnum(_, substs) => substs, + _ => span_bug!(pat.span, "struct variant is not an ADT") + }; + self.demand_eqtype(pat.span, expected, pat_ty); + self.check_struct_pat_fields(pat.span, fields, variant, &item_substs, etc); + + self.write_ty(pat.id, pat_ty); + self.write_substs(pat.id, ty::ItemSubsts { + substs: item_substs + }); + } + + fn check_pat_enum(&self, + pat: &hir::Pat, + path: &hir::Path, + subpats: Option<&'gcx [P]>, + expected: Ty<'tcx>, + is_tuple_struct_pat: bool) + { + // Typecheck the path. + let tcx = self.tcx; + + let path_res = match tcx.def_map.borrow().get(&pat.id) { + Some(&path_res) if path_res.base_def != Def::Err => path_res, + _ => { + self.set_tainted_by_errors(); + self.write_error(pat.id); + + if let Some(subpats) = subpats { + for pat in subpats { + self.check_pat(&pat, tcx.types.err); + } + } + + return; + } + }; + + let (opt_ty, segments, def) = match self.resolve_ty_and_def_ufcs(path_res, + None, path, + pat.span, pat.id) { + Some(resolution) => resolution, + // Error handling done inside resolve_ty_and_def_ufcs, so if + // resolution fails just return. + None => {return;} + }; + + // Items that were partially resolved before should have been resolved to + // associated constants (i.e. not methods). + if path_res.depth != 0 && !self.check_assoc_item_is_const(def, pat.span) { + self.write_error(pat.id); return; } - }; - let pat_ty = self.instantiate_type(def.def_id(), path); - let item_substs = match pat_ty.sty { - ty::TyStruct(_, substs) | ty::TyEnum(_, substs) => substs, - _ => span_bug!(pat.span, "struct variant is not an ADT") - }; - self.demand_eqtype(pat.span, expected, pat_ty); - self.check_struct_pat_fields(pat.span, fields, variant, &item_substs, etc); + let enum_def = def.variant_def_ids() + .map_or_else(|| def.def_id(), |(enum_def, _)| enum_def); - self.write_ty(pat.id, pat_ty); - self.write_substs(pat.id, ty::ItemSubsts { - substs: item_substs - }); -} + let ctor_scheme = tcx.lookup_item_type(enum_def); + let ctor_predicates = tcx.lookup_predicates(enum_def); + let path_scheme = if ctor_scheme.ty.is_fn() { + let fn_ret = tcx.no_late_bound_regions(&ctor_scheme.ty.fn_ret()).unwrap(); + ty::TypeScheme { + ty: fn_ret.unwrap(), + generics: ctor_scheme.generics, + } + } else { + ctor_scheme + }; + self.instantiate_path(segments, path_scheme, &ctor_predicates, + opt_ty, def, pat.span, pat.id); -fn check_pat_enum(&self, - pat: &hir::Pat, - path: &hir::Path, - subpats: Option<&'gcx [P]>, - expected: Ty<'tcx>, - is_tuple_struct_pat: bool) -{ - // Typecheck the path. - let tcx = self.tcx; - - let path_res = match tcx.def_map.borrow().get(&pat.id) { - Some(&path_res) if path_res.base_def != Def::Err => path_res, - _ => { - self.set_tainted_by_errors(); + let report_bad_struct_kind = |is_warning| { + bad_struct_kind_err(tcx.sess, pat, path, is_warning); + if is_warning { return; } self.write_error(pat.id); - if let Some(subpats) = subpats { for pat in subpats { self.check_pat(&pat, tcx.types.err); } } + }; + // If we didn't have a fully resolved path to start with, we had an + // associated const, and we should quit now, since the rest of this + // function uses checks specific to structs and enums. + if path_res.depth != 0 { + if is_tuple_struct_pat { + report_bad_struct_kind(false); + } else { + let pat_ty = self.node_ty(pat.id); + self.demand_suptype(pat.span, expected, pat_ty); + } return; } - }; - let (opt_ty, segments, def) = match self.resolve_ty_and_def_ufcs(path_res, - None, path, - pat.span, pat.id) { - Some(resolution) => resolution, - // Error handling done inside resolve_ty_and_def_ufcs, so if - // resolution fails just return. - None => {return;} - }; + let pat_ty = self.node_ty(pat.id); + self.demand_eqtype(pat.span, expected, pat_ty); - // Items that were partially resolved before should have been resolved to - // associated constants (i.e. not methods). - if path_res.depth != 0 && !self.check_assoc_item_is_const(def, pat.span) { - self.write_error(pat.id); - return; - } - - let enum_def = def.variant_def_ids() - .map_or_else(|| def.def_id(), |(enum_def, _)| enum_def); - - let ctor_scheme = tcx.lookup_item_type(enum_def); - let ctor_predicates = tcx.lookup_predicates(enum_def); - let path_scheme = if ctor_scheme.ty.is_fn() { - let fn_ret = tcx.no_late_bound_regions(&ctor_scheme.ty.fn_ret()).unwrap(); - ty::TypeScheme { - ty: fn_ret.unwrap(), - generics: ctor_scheme.generics, - } - } else { - ctor_scheme - }; - self.instantiate_path(segments, path_scheme, &ctor_predicates, - opt_ty, def, pat.span, pat.id); - - let report_bad_struct_kind = |is_warning| { - bad_struct_kind_err(tcx.sess, pat, path, is_warning); - if is_warning { return; } - self.write_error(pat.id); - if let Some(subpats) = subpats { - for pat in subpats { - self.check_pat(&pat, tcx.types.err); + let real_path_ty = self.node_ty(pat.id); + let (kind_name, variant, expected_substs) = match real_path_ty.sty { + ty::TyEnum(enum_def, expected_substs) => { + let variant = enum_def.variant_of_def(def); + ("variant", variant, expected_substs) } - } - }; - - // If we didn't have a fully resolved path to start with, we had an - // associated const, and we should quit now, since the rest of this - // function uses checks specific to structs and enums. - if path_res.depth != 0 { - if is_tuple_struct_pat { - report_bad_struct_kind(false); - } else { - let pat_ty = self.node_ty(pat.id); - self.demand_suptype(pat.span, expected, pat_ty); - } - return; - } - - let pat_ty = self.node_ty(pat.id); - self.demand_eqtype(pat.span, expected, pat_ty); - - let real_path_ty = self.node_ty(pat.id); - let (kind_name, variant, expected_substs) = match real_path_ty.sty { - ty::TyEnum(enum_def, expected_substs) => { - let variant = enum_def.variant_of_def(def); - ("variant", variant, expected_substs) - } - ty::TyStruct(struct_def, expected_substs) => { - let variant = struct_def.struct_variant(); - ("struct", variant, expected_substs) - } - _ => { - report_bad_struct_kind(false); - return; - } - }; - - match (is_tuple_struct_pat, variant.kind()) { - (true, ty::VariantKind::Unit) => { - // Matching unit structs with tuple variant patterns (`UnitVariant(..)`) - // is allowed for backward compatibility. - report_bad_struct_kind(true); - } - (_, ty::VariantKind::Struct) => { - report_bad_struct_kind(false); - return - } - _ => {} - } - - if let Some(subpats) = subpats { - if subpats.len() == variant.fields.len() { - for (subpat, field) in subpats.iter().zip(&variant.fields) { - let field_ty = self.field_ty(subpat.span, field, expected_substs); - self.check_pat(&subpat, field_ty); + ty::TyStruct(struct_def, expected_substs) => { + let variant = struct_def.struct_variant(); + ("struct", variant, expected_substs) } - } else if variant.fields.is_empty() { - span_err!(tcx.sess, pat.span, E0024, - "this pattern has {} field{}, but the corresponding {} has no fields", - subpats.len(), if subpats.len() == 1 {""} else {"s"}, kind_name); - - for pat in subpats { - self.check_pat(&pat, tcx.types.err); - } - } else { - span_err!(tcx.sess, pat.span, E0023, - "this pattern has {} field{}, but the corresponding {} has {} field{}", - subpats.len(), if subpats.len() == 1 {""} else {"s"}, - kind_name, - variant.fields.len(), if variant.fields.len() == 1 {""} else {"s"}); - - for pat in subpats { - self.check_pat(&pat, tcx.types.err); - } - } - } -} - -/// `path` is the AST path item naming the type of this struct. -/// `fields` is the field patterns of the struct pattern. -/// `struct_fields` describes the type of each field of the struct. -/// `struct_id` is the ID of the struct. -/// `etc` is true if the pattern said '...' and false otherwise. -pub fn check_struct_pat_fields(&self, - span: Span, - fields: &'gcx [Spanned], - variant: ty::VariantDef<'tcx>, - substs: &Substs<'tcx>, - etc: bool) { - let tcx = self.tcx; - - // Index the struct fields' types. - let field_map = variant.fields - .iter() - .map(|field| (field.name, field)) - .collect::>(); - - // Keep track of which fields have already appeared in the pattern. - let mut used_fields = FnvHashMap(); - - // Typecheck each field. - for &Spanned { node: ref field, span } in fields { - let field_ty = match used_fields.entry(field.name) { - Occupied(occupied) => { - let mut err = struct_span_err!(tcx.sess, span, E0025, - "field `{}` bound multiple times in the pattern", - field.name); - span_note!(&mut err, *occupied.get(), - "field `{}` previously bound here", - field.name); - err.emit(); - tcx.types.err - } - Vacant(vacant) => { - vacant.insert(span); - field_map.get(&field.name) - .map(|f| self.field_ty(span, f, substs)) - .unwrap_or_else(|| { - span_err!(tcx.sess, span, E0026, - "struct `{}` does not have a field named `{}`", - tcx.item_path_str(variant.did), - field.name); - tcx.types.err - }) + _ => { + report_bad_struct_kind(false); + return; } }; - self.check_pat(&field.pat, field_ty); + match (is_tuple_struct_pat, variant.kind()) { + (true, ty::VariantKind::Unit) => { + // Matching unit structs with tuple variant patterns (`UnitVariant(..)`) + // is allowed for backward compatibility. + report_bad_struct_kind(true); + } + (_, ty::VariantKind::Struct) => { + report_bad_struct_kind(false); + return + } + _ => {} + } + + if let Some(subpats) = subpats { + if subpats.len() == variant.fields.len() { + for (subpat, field) in subpats.iter().zip(&variant.fields) { + let field_ty = self.field_ty(subpat.span, field, expected_substs); + self.check_pat(&subpat, field_ty); + } + } else if variant.fields.is_empty() { + span_err!(tcx.sess, pat.span, E0024, + "this pattern has {} field{}, but the corresponding {} has no fields", + subpats.len(), if subpats.len() == 1 {""} else {"s"}, kind_name); + + for pat in subpats { + self.check_pat(&pat, tcx.types.err); + } + } else { + span_err!(tcx.sess, pat.span, E0023, + "this pattern has {} field{}, but the corresponding {} has {} field{}", + subpats.len(), if subpats.len() == 1 {""} else {"s"}, + kind_name, + variant.fields.len(), if variant.fields.len() == 1 {""} else {"s"}); + + for pat in subpats { + self.check_pat(&pat, tcx.types.err); + } + } + } } - // Report an error if not all the fields were specified. - if !etc { - for field in variant.fields + /// `path` is the AST path item naming the type of this struct. + /// `fields` is the field patterns of the struct pattern. + /// `struct_fields` describes the type of each field of the struct. + /// `struct_id` is the ID of the struct. + /// `etc` is true if the pattern said '...' and false otherwise. + pub fn check_struct_pat_fields(&self, + span: Span, + fields: &'gcx [Spanned], + variant: ty::VariantDef<'tcx>, + substs: &Substs<'tcx>, + etc: bool) { + let tcx = self.tcx; + + // Index the struct fields' types. + let field_map = variant.fields .iter() - .filter(|field| !used_fields.contains_key(&field.name)) { - span_err!(tcx.sess, span, E0027, - "pattern does not mention field `{}`", - field.name); + .map(|field| (field.name, field)) + .collect::>(); + + // Keep track of which fields have already appeared in the pattern. + let mut used_fields = FnvHashMap(); + + // Typecheck each field. + for &Spanned { node: ref field, span } in fields { + let field_ty = match used_fields.entry(field.name) { + Occupied(occupied) => { + let mut err = struct_span_err!(tcx.sess, span, E0025, + "field `{}` bound multiple times \ + in the pattern", + field.name); + span_note!(&mut err, *occupied.get(), + "field `{}` previously bound here", + field.name); + err.emit(); + tcx.types.err + } + Vacant(vacant) => { + vacant.insert(span); + field_map.get(&field.name) + .map(|f| self.field_ty(span, f, substs)) + .unwrap_or_else(|| { + span_err!(tcx.sess, span, E0026, + "struct `{}` does not have a field named `{}`", + tcx.item_path_str(variant.did), + field.name); + tcx.types.err + }) + } + }; + + self.check_pat(&field.pat, field_ty); + } + + // Report an error if not all the fields were specified. + if !etc { + for field in variant.fields + .iter() + .filter(|field| !used_fields.contains_key(&field.name)) { + span_err!(tcx.sess, span, E0027, + "pattern does not mention field `{}`", + field.name); + } } } } -} diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 9de78168fe7..7493ca70f55 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -64,267 +64,267 @@ enum CallStep<'tcx> { } impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { -pub fn check_call(&self, - call_expr: &'gcx hir::Expr, - callee_expr: &'gcx hir::Expr, - arg_exprs: &'gcx [P], - expected: Expectation<'tcx>) -{ - self.check_expr(callee_expr); - let original_callee_ty = self.expr_ty(callee_expr); - let (callee_ty, _, result) = - self.autoderef(callee_expr.span, - original_callee_ty, - || Some(callee_expr), - UnresolvedTypeAction::Error, - LvaluePreference::NoPreference, - |adj_ty, idx| { - self.try_overloaded_call_step(call_expr, callee_expr, adj_ty, idx) - }); + pub fn check_call(&self, + call_expr: &'gcx hir::Expr, + callee_expr: &'gcx hir::Expr, + arg_exprs: &'gcx [P], + expected: Expectation<'tcx>) + { + self.check_expr(callee_expr); + let original_callee_ty = self.expr_ty(callee_expr); + let (callee_ty, _, result) = + self.autoderef(callee_expr.span, + original_callee_ty, + || Some(callee_expr), + UnresolvedTypeAction::Error, + LvaluePreference::NoPreference, + |adj_ty, idx| { + self.try_overloaded_call_step(call_expr, callee_expr, adj_ty, idx) + }); - match result { - None => { - // this will report an error since original_callee_ty is not a fn - self.confirm_builtin_call(call_expr, original_callee_ty, arg_exprs, expected); - } - - Some(CallStep::Builtin) => { - self.confirm_builtin_call(call_expr, callee_ty, arg_exprs, expected); - } - - Some(CallStep::DeferredClosure(fn_sig)) => { - self.confirm_deferred_closure_call(call_expr, arg_exprs, expected, fn_sig); - } - - Some(CallStep::Overloaded(method_callee)) => { - self.confirm_overloaded_call(call_expr, callee_expr, - arg_exprs, expected, method_callee); - } - } -} - -fn try_overloaded_call_step(&self, - call_expr: &'gcx hir::Expr, - callee_expr: &'gcx hir::Expr, - adjusted_ty: Ty<'tcx>, - autoderefs: usize) - -> Option> -{ - debug!("try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?}, autoderefs={})", - call_expr, - adjusted_ty, - autoderefs); - - // If the callee is a bare function or a closure, then we're all set. - match self.structurally_resolved_type(callee_expr.span, adjusted_ty).sty { - ty::TyFnDef(..) | ty::TyFnPtr(_) => { - self.write_autoderef_adjustment(callee_expr.id, autoderefs); - return Some(CallStep::Builtin); - } - - ty::TyClosure(def_id, substs) => { - assert_eq!(def_id.krate, LOCAL_CRATE); - - // Check whether this is a call to a closure where we - // haven't yet decided on whether the closure is fn vs - // fnmut vs fnonce. If so, we have to defer further processing. - if self.closure_kind(def_id).is_none() { - let closure_ty = - self.closure_type(def_id, substs); - let fn_sig = - self.replace_late_bound_regions_with_fresh_var(call_expr.span, - infer::FnCall, - &closure_ty.sig).0; - self.record_deferred_call_resolution(def_id, Box::new(CallResolution { - call_expr: call_expr, - callee_expr: callee_expr, - adjusted_ty: adjusted_ty, - autoderefs: autoderefs, - fn_sig: fn_sig.clone(), - closure_def_id: def_id - })); - return Some(CallStep::DeferredClosure(fn_sig)); + match result { + None => { + // this will report an error since original_callee_ty is not a fn + self.confirm_builtin_call(call_expr, original_callee_ty, arg_exprs, expected); } - } - // Hack: we know that there are traits implementing Fn for &F - // where F:Fn and so forth. In the particular case of types - // like `x: &mut FnMut()`, if there is a call `x()`, we would - // normally translate to `FnMut::call_mut(&mut x, ())`, but - // that winds up requiring `mut x: &mut FnMut()`. A little - // over the top. The simplest fix by far is to just ignore - // this case and deref again, so we wind up with - // `FnMut::call_mut(&mut *x, ())`. - ty::TyRef(..) if autoderefs == 0 => { - return None; - } + Some(CallStep::Builtin) => { + self.confirm_builtin_call(call_expr, callee_ty, arg_exprs, expected); + } - _ => {} - } + Some(CallStep::DeferredClosure(fn_sig)) => { + self.confirm_deferred_closure_call(call_expr, arg_exprs, expected, fn_sig); + } - self.try_overloaded_call_traits(call_expr, callee_expr, adjusted_ty, autoderefs) - .map(|method_callee| CallStep::Overloaded(method_callee)) -} - -fn try_overloaded_call_traits(&self, - call_expr: &hir::Expr, - callee_expr: &hir::Expr, - adjusted_ty: Ty<'tcx>, - autoderefs: usize) - -> Option> -{ - // Try the options that are least restrictive on the caller first. - for &(opt_trait_def_id, method_name) in &[ - (self.tcx.lang_items.fn_trait(), token::intern("call")), - (self.tcx.lang_items.fn_mut_trait(), token::intern("call_mut")), - (self.tcx.lang_items.fn_once_trait(), token::intern("call_once")), - ] { - let trait_def_id = match opt_trait_def_id { - Some(def_id) => def_id, - None => continue, - }; - - match self.lookup_method_in_trait_adjusted(call_expr.span, - Some(&callee_expr), - method_name, - trait_def_id, - autoderefs, - false, - adjusted_ty, - None) { - None => continue, - Some(method_callee) => { - return Some(method_callee); + Some(CallStep::Overloaded(method_callee)) => { + self.confirm_overloaded_call(call_expr, callee_expr, + arg_exprs, expected, method_callee); } } } - None -} + fn try_overloaded_call_step(&self, + call_expr: &'gcx hir::Expr, + callee_expr: &'gcx hir::Expr, + adjusted_ty: Ty<'tcx>, + autoderefs: usize) + -> Option> + { + debug!("try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?}, autoderefs={})", + call_expr, + adjusted_ty, + autoderefs); -fn confirm_builtin_call(&self, - call_expr: &hir::Expr, - callee_ty: Ty<'tcx>, - arg_exprs: &'gcx [P], - expected: Expectation<'tcx>) -{ - let error_fn_sig; + // If the callee is a bare function or a closure, then we're all set. + match self.structurally_resolved_type(callee_expr.span, adjusted_ty).sty { + ty::TyFnDef(..) | ty::TyFnPtr(_) => { + self.write_autoderef_adjustment(callee_expr.id, autoderefs); + return Some(CallStep::Builtin); + } - let fn_sig = match callee_ty.sty { - ty::TyFnDef(_, _, &ty::BareFnTy {ref sig, ..}) | - ty::TyFnPtr(&ty::BareFnTy {ref sig, ..}) => { - sig - } - _ => { - let mut err = self.type_error_struct(call_expr.span, |actual| { - format!("expected function, found `{}`", actual) - }, callee_ty, None); + ty::TyClosure(def_id, substs) => { + assert_eq!(def_id.krate, LOCAL_CRATE); - if let hir::ExprCall(ref expr, _) = call_expr.node { - let tcx = self.tcx; - if let Some(pr) = tcx.def_map.borrow().get(&expr.id) { - if pr.depth == 0 && pr.base_def != Def::Err { - if let Some(span) = tcx.map.span_if_local(pr.def_id()) { - err.span_note(span, "defined here"); - } - } + // Check whether this is a call to a closure where we + // haven't yet decided on whether the closure is fn vs + // fnmut vs fnonce. If so, we have to defer further processing. + if self.closure_kind(def_id).is_none() { + let closure_ty = + self.closure_type(def_id, substs); + let fn_sig = + self.replace_late_bound_regions_with_fresh_var(call_expr.span, + infer::FnCall, + &closure_ty.sig).0; + self.record_deferred_call_resolution(def_id, Box::new(CallResolution { + call_expr: call_expr, + callee_expr: callee_expr, + adjusted_ty: adjusted_ty, + autoderefs: autoderefs, + fn_sig: fn_sig.clone(), + closure_def_id: def_id + })); + return Some(CallStep::DeferredClosure(fn_sig)); } } - err.emit(); + // Hack: we know that there are traits implementing Fn for &F + // where F:Fn and so forth. In the particular case of types + // like `x: &mut FnMut()`, if there is a call `x()`, we would + // normally translate to `FnMut::call_mut(&mut x, ())`, but + // that winds up requiring `mut x: &mut FnMut()`. A little + // over the top. The simplest fix by far is to just ignore + // this case and deref again, so we wind up with + // `FnMut::call_mut(&mut *x, ())`. + ty::TyRef(..) if autoderefs == 0 => { + return None; + } - // This is the "default" function signature, used in case of error. - // In that case, we check each argument against "error" in order to - // set up all the node type bindings. - error_fn_sig = ty::Binder(ty::FnSig { - inputs: self.err_args(arg_exprs.len()), - output: ty::FnConverging(self.tcx.types.err), - variadic: false - }); - - &error_fn_sig + _ => {} } - }; - // Replace any late-bound regions that appear in the function - // signature with region variables. We also have to - // renormalize the associated types at this point, since they - // previously appeared within a `Binder<>` and hence would not - // have been normalized before. - let fn_sig = - self.replace_late_bound_regions_with_fresh_var(call_expr.span, - infer::FnCall, - fn_sig).0; - let fn_sig = - self.normalize_associated_types_in(call_expr.span, &fn_sig); + self.try_overloaded_call_traits(call_expr, callee_expr, adjusted_ty, autoderefs) + .map(|method_callee| CallStep::Overloaded(method_callee)) + } - // Call the generic checker. - let expected_arg_tys = self.expected_types_for_fn_args(call_expr.span, - expected, - fn_sig.output, - &fn_sig.inputs); - self.check_argument_types(call_expr.span, - &fn_sig.inputs, - &expected_arg_tys[..], - arg_exprs, - fn_sig.variadic, - TupleArgumentsFlag::DontTupleArguments); + fn try_overloaded_call_traits(&self, + call_expr: &hir::Expr, + callee_expr: &hir::Expr, + adjusted_ty: Ty<'tcx>, + autoderefs: usize) + -> Option> + { + // Try the options that are least restrictive on the caller first. + for &(opt_trait_def_id, method_name) in &[ + (self.tcx.lang_items.fn_trait(), token::intern("call")), + (self.tcx.lang_items.fn_mut_trait(), token::intern("call_mut")), + (self.tcx.lang_items.fn_once_trait(), token::intern("call_once")), + ] { + let trait_def_id = match opt_trait_def_id { + Some(def_id) => def_id, + None => continue, + }; - self.write_call(call_expr, fn_sig.output); -} + match self.lookup_method_in_trait_adjusted(call_expr.span, + Some(&callee_expr), + method_name, + trait_def_id, + autoderefs, + false, + adjusted_ty, + None) { + None => continue, + Some(method_callee) => { + return Some(method_callee); + } + } + } -fn confirm_deferred_closure_call(&self, - call_expr: &hir::Expr, - arg_exprs: &'gcx [P], - expected: Expectation<'tcx>, - fn_sig: ty::FnSig<'tcx>) -{ - // `fn_sig` is the *signature* of the cosure being called. We - // don't know the full details yet (`Fn` vs `FnMut` etc), but we - // do know the types expected for each argument and the return - // type. + None + } - let expected_arg_tys = - self.expected_types_for_fn_args(call_expr.span, - expected, - fn_sig.output.clone(), - &fn_sig.inputs); + fn confirm_builtin_call(&self, + call_expr: &hir::Expr, + callee_ty: Ty<'tcx>, + arg_exprs: &'gcx [P], + expected: Expectation<'tcx>) + { + let error_fn_sig; - self.check_argument_types(call_expr.span, - &fn_sig.inputs, - &expected_arg_tys, - arg_exprs, - fn_sig.variadic, - TupleArgumentsFlag::TupleArguments); + let fn_sig = match callee_ty.sty { + ty::TyFnDef(_, _, &ty::BareFnTy {ref sig, ..}) | + ty::TyFnPtr(&ty::BareFnTy {ref sig, ..}) => { + sig + } + _ => { + let mut err = self.type_error_struct(call_expr.span, |actual| { + format!("expected function, found `{}`", actual) + }, callee_ty, None); - self.write_call(call_expr, fn_sig.output); -} + if let hir::ExprCall(ref expr, _) = call_expr.node { + let tcx = self.tcx; + if let Some(pr) = tcx.def_map.borrow().get(&expr.id) { + if pr.depth == 0 && pr.base_def != Def::Err { + if let Some(span) = tcx.map.span_if_local(pr.def_id()) { + err.span_note(span, "defined here"); + } + } + } + } -fn confirm_overloaded_call(&self, - call_expr: &hir::Expr, - callee_expr: &'gcx hir::Expr, - arg_exprs: &'gcx [P], - expected: Expectation<'tcx>, - method_callee: ty::MethodCallee<'tcx>) -{ - let output_type = - self.check_method_argument_types(call_expr.span, - method_callee.ty, - callee_expr, - arg_exprs, - TupleArgumentsFlag::TupleArguments, - expected); - self.write_call(call_expr, output_type); + err.emit(); - self.write_overloaded_call_method_map(call_expr, method_callee); -} + // This is the "default" function signature, used in case of error. + // In that case, we check each argument against "error" in order to + // set up all the node type bindings. + error_fn_sig = ty::Binder(ty::FnSig { + inputs: self.err_args(arg_exprs.len()), + output: ty::FnConverging(self.tcx.types.err), + variadic: false + }); -fn write_overloaded_call_method_map(&self, - call_expr: &hir::Expr, - method_callee: ty::MethodCallee<'tcx>) { - let method_call = ty::MethodCall::expr(call_expr.id); - self.tables.borrow_mut().method_map.insert(method_call, method_callee); -} + &error_fn_sig + } + }; + + // Replace any late-bound regions that appear in the function + // signature with region variables. We also have to + // renormalize the associated types at this point, since they + // previously appeared within a `Binder<>` and hence would not + // have been normalized before. + let fn_sig = + self.replace_late_bound_regions_with_fresh_var(call_expr.span, + infer::FnCall, + fn_sig).0; + let fn_sig = + self.normalize_associated_types_in(call_expr.span, &fn_sig); + + // Call the generic checker. + let expected_arg_tys = self.expected_types_for_fn_args(call_expr.span, + expected, + fn_sig.output, + &fn_sig.inputs); + self.check_argument_types(call_expr.span, + &fn_sig.inputs, + &expected_arg_tys[..], + arg_exprs, + fn_sig.variadic, + TupleArgumentsFlag::DontTupleArguments); + + self.write_call(call_expr, fn_sig.output); + } + + fn confirm_deferred_closure_call(&self, + call_expr: &hir::Expr, + arg_exprs: &'gcx [P], + expected: Expectation<'tcx>, + fn_sig: ty::FnSig<'tcx>) + { + // `fn_sig` is the *signature* of the cosure being called. We + // don't know the full details yet (`Fn` vs `FnMut` etc), but we + // do know the types expected for each argument and the return + // type. + + let expected_arg_tys = + self.expected_types_for_fn_args(call_expr.span, + expected, + fn_sig.output.clone(), + &fn_sig.inputs); + + self.check_argument_types(call_expr.span, + &fn_sig.inputs, + &expected_arg_tys, + arg_exprs, + fn_sig.variadic, + TupleArgumentsFlag::TupleArguments); + + self.write_call(call_expr, fn_sig.output); + } + + fn confirm_overloaded_call(&self, + call_expr: &hir::Expr, + callee_expr: &'gcx hir::Expr, + arg_exprs: &'gcx [P], + expected: Expectation<'tcx>, + method_callee: ty::MethodCallee<'tcx>) + { + let output_type = + self.check_method_argument_types(call_expr.span, + method_callee.ty, + callee_expr, + arg_exprs, + TupleArgumentsFlag::TupleArguments, + expected); + self.write_call(call_expr, output_type); + + self.write_overloaded_call_method_map(call_expr, method_callee); + } + + fn write_overloaded_call_method_map(&self, + call_expr: &hir::Expr, + method_callee: ty::MethodCallee<'tcx>) { + let method_call = ty::MethodCall::expr(call_expr.id); + self.tables.borrow_mut().method_map.insert(method_call, method_callee); + } } #[derive(Debug)] diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index bdf26eab20f..690250edb8c 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -73,26 +73,26 @@ enum UnsizeKind<'tcx> { } impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { -/// Returns the kind of unsize information of t, or None -/// if t is sized or it is unknown. -fn unsize_kind(&self, t: Ty<'tcx>) -> Option> { - match t.sty { - ty::TySlice(_) | ty::TyStr => Some(UnsizeKind::Length), - ty::TyTrait(ref tty) => Some(UnsizeKind::Vtable(tty.principal_def_id())), - ty::TyStruct(def, substs) => { - // FIXME(arielb1): do some kind of normalization - match def.struct_variant().fields.last() { - None => None, - Some(f) => self.unsize_kind(f.ty(self.tcx, substs)) + /// Returns the kind of unsize information of t, or None + /// if t is sized or it is unknown. + fn unsize_kind(&self, t: Ty<'tcx>) -> Option> { + match t.sty { + ty::TySlice(_) | ty::TyStr => Some(UnsizeKind::Length), + ty::TyTrait(ref tty) => Some(UnsizeKind::Vtable(tty.principal_def_id())), + ty::TyStruct(def, substs) => { + // FIXME(arielb1): do some kind of normalization + match def.struct_variant().fields.last() { + None => None, + Some(f) => self.unsize_kind(f.ty(self.tcx, substs)) + } } + // We should really try to normalize here. + ty::TyProjection(ref pi) => Some(UnsizeKind::OfProjection(pi)), + ty::TyParam(ref p) => Some(UnsizeKind::OfParam(p)), + _ => None } - // We should really try to normalize here. - ty::TyProjection(ref pi) => Some(UnsizeKind::OfProjection(pi)), - ty::TyParam(ref p) => Some(UnsizeKind::OfParam(p)), - _ => None } } -} #[derive(Copy, Clone)] enum CastError { diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 43c1f9d367e..d3396eb4c1b 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -20,227 +20,227 @@ use syntax::abi::Abi; use rustc::hir; impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { -pub fn check_expr_closure(&self, - expr: &hir::Expr, - _capture: hir::CaptureClause, - decl: &'gcx hir::FnDecl, - body: &'gcx hir::Block, - expected: Expectation<'tcx>) { - debug!("check_expr_closure(expr={:?},expected={:?})", - expr, - expected); + pub fn check_expr_closure(&self, + expr: &hir::Expr, + _capture: hir::CaptureClause, + decl: &'gcx hir::FnDecl, + body: &'gcx hir::Block, + expected: Expectation<'tcx>) { + debug!("check_expr_closure(expr={:?},expected={:?})", + expr, + expected); - // It's always helpful for inference if we know the kind of - // closure sooner rather than later, so first examine the expected - // type, and see if can glean a closure kind from there. - let (expected_sig,expected_kind) = match expected.to_option(self) { - Some(ty) => self.deduce_expectations_from_expected_type(ty), - None => (None, None) - }; - self.check_closure(expr, expected_kind, decl, body, expected_sig) -} - -fn check_closure(&self, - expr: &hir::Expr, - opt_kind: Option, - decl: &'gcx hir::FnDecl, - body: &'gcx hir::Block, - expected_sig: Option>) { - let expr_def_id = self.tcx.map.local_def_id(expr.id); - - debug!("check_closure opt_kind={:?} expected_sig={:?}", - opt_kind, - expected_sig); - - let mut fn_ty = AstConv::ty_of_closure(self, - hir::Unsafety::Normal, - decl, - Abi::RustCall, - expected_sig); - - // Create type variables (for now) to represent the transformed - // types of upvars. These will be unified during the upvar - // inference phase (`upvar.rs`). - let num_upvars = self.tcx.with_freevars(expr.id, |fv| fv.len()); - let upvar_tys = self.next_ty_vars(num_upvars); - - debug!("check_closure: expr.id={:?} upvar_tys={:?}", - expr.id, upvar_tys); - - let closure_type = self.tcx.mk_closure(expr_def_id, - self.parameter_environment.free_substs, - upvar_tys); - - self.write_ty(expr.id, closure_type); - - let fn_sig = self.tcx.liberate_late_bound_regions( - self.tcx.region_maps.call_site_extent(expr.id, body.id), &fn_ty.sig); - - check_fn(self, hir::Unsafety::Normal, expr.id, &fn_sig, decl, expr.id, &body); - - // Tuple up the arguments and insert the resulting function type into - // the `closures` table. - fn_ty.sig.0.inputs = vec![self.tcx.mk_tup(fn_ty.sig.0.inputs)]; - - debug!("closure for {:?} --> sig={:?} opt_kind={:?}", - expr_def_id, - fn_ty.sig, - opt_kind); - - self.tables.borrow_mut().closure_tys.insert(expr_def_id, fn_ty); - match opt_kind { - Some(kind) => { self.tables.borrow_mut().closure_kinds.insert(expr_def_id, kind); } - None => { } + // It's always helpful for inference if we know the kind of + // closure sooner rather than later, so first examine the expected + // type, and see if can glean a closure kind from there. + let (expected_sig,expected_kind) = match expected.to_option(self) { + Some(ty) => self.deduce_expectations_from_expected_type(ty), + None => (None, None) + }; + self.check_closure(expr, expected_kind, decl, body, expected_sig) } -} -fn deduce_expectations_from_expected_type(&self, expected_ty: Ty<'tcx>) - -> (Option>,Option) -{ - debug!("deduce_expectations_from_expected_type(expected_ty={:?})", - expected_ty); + fn check_closure(&self, + expr: &hir::Expr, + opt_kind: Option, + decl: &'gcx hir::FnDecl, + body: &'gcx hir::Block, + expected_sig: Option>) { + let expr_def_id = self.tcx.map.local_def_id(expr.id); - match expected_ty.sty { - ty::TyTrait(ref object_type) => { - let proj_bounds = object_type.projection_bounds_with_self_ty(self.tcx, - self.tcx.types.err); - let sig = proj_bounds.iter() - .filter_map(|pb| self.deduce_sig_from_projection(pb)) - .next(); - let kind = self.tcx.lang_items.fn_trait_kind(object_type.principal_def_id()); - (sig, kind) - } - ty::TyInfer(ty::TyVar(vid)) => { - self.deduce_expectations_from_obligations(vid) - } - _ => { - (None, None) + debug!("check_closure opt_kind={:?} expected_sig={:?}", + opt_kind, + expected_sig); + + let mut fn_ty = AstConv::ty_of_closure(self, + hir::Unsafety::Normal, + decl, + Abi::RustCall, + expected_sig); + + // Create type variables (for now) to represent the transformed + // types of upvars. These will be unified during the upvar + // inference phase (`upvar.rs`). + let num_upvars = self.tcx.with_freevars(expr.id, |fv| fv.len()); + let upvar_tys = self.next_ty_vars(num_upvars); + + debug!("check_closure: expr.id={:?} upvar_tys={:?}", + expr.id, upvar_tys); + + let closure_type = self.tcx.mk_closure(expr_def_id, + self.parameter_environment.free_substs, + upvar_tys); + + self.write_ty(expr.id, closure_type); + + let fn_sig = self.tcx.liberate_late_bound_regions( + self.tcx.region_maps.call_site_extent(expr.id, body.id), &fn_ty.sig); + + check_fn(self, hir::Unsafety::Normal, expr.id, &fn_sig, decl, expr.id, &body); + + // Tuple up the arguments and insert the resulting function type into + // the `closures` table. + fn_ty.sig.0.inputs = vec![self.tcx.mk_tup(fn_ty.sig.0.inputs)]; + + debug!("closure for {:?} --> sig={:?} opt_kind={:?}", + expr_def_id, + fn_ty.sig, + opt_kind); + + self.tables.borrow_mut().closure_tys.insert(expr_def_id, fn_ty); + match opt_kind { + Some(kind) => { self.tables.borrow_mut().closure_kinds.insert(expr_def_id, kind); } + None => { } } } -} -fn deduce_expectations_from_obligations(&self, expected_vid: ty::TyVid) - -> (Option>, Option) -{ - let fulfillment_cx = self.fulfillment_cx.borrow(); - // Here `expected_ty` is known to be a type inference variable. + fn deduce_expectations_from_expected_type(&self, expected_ty: Ty<'tcx>) + -> (Option>,Option) + { + debug!("deduce_expectations_from_expected_type(expected_ty={:?})", + expected_ty); - let expected_sig = - fulfillment_cx - .pending_obligations() - .iter() - .map(|obligation| &obligation.obligation) - .filter_map(|obligation| { - debug!("deduce_expectations_from_obligations: obligation.predicate={:?}", - obligation.predicate); - - match obligation.predicate { - // Given a Projection predicate, we can potentially infer - // the complete signature. - ty::Predicate::Projection(ref proj_predicate) => { - let trait_ref = proj_predicate.to_poly_trait_ref(); - self.self_type_matches_expected_vid(trait_ref, expected_vid) - .and_then(|_| self.deduce_sig_from_projection(proj_predicate)) - } - _ => { - None - } + match expected_ty.sty { + ty::TyTrait(ref object_type) => { + let proj_bounds = object_type.projection_bounds_with_self_ty(self.tcx, + self.tcx.types.err); + let sig = proj_bounds.iter() + .filter_map(|pb| self.deduce_sig_from_projection(pb)) + .next(); + let kind = self.tcx.lang_items.fn_trait_kind(object_type.principal_def_id()); + (sig, kind) } - }) - .next(); - - // Even if we can't infer the full signature, we may be able to - // infer the kind. This can occur if there is a trait-reference - // like `F : Fn`. Note that due to subtyping we could encounter - // many viable options, so pick the most restrictive. - let expected_kind = - fulfillment_cx - .pending_obligations() - .iter() - .map(|obligation| &obligation.obligation) - .filter_map(|obligation| { - let opt_trait_ref = match obligation.predicate { - ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref()), - ty::Predicate::Trait(ref data) => Some(data.to_poly_trait_ref()), - ty::Predicate::Equate(..) => None, - ty::Predicate::RegionOutlives(..) => None, - ty::Predicate::TypeOutlives(..) => None, - ty::Predicate::WellFormed(..) => None, - ty::Predicate::ObjectSafe(..) => None, - ty::Predicate::Rfc1592(..) => None, - - // NB: This predicate is created by breaking down a - // `ClosureType: FnFoo()` predicate, where - // `ClosureType` represents some `TyClosure`. It can't - // possibly be referring to the current closure, - // because we haven't produced the `TyClosure` for - // this closure yet; this is exactly why the other - // code is looking for a self type of a unresolved - // inference variable. - ty::Predicate::ClosureKind(..) => None, - }; - opt_trait_ref - .and_then(|trait_ref| self.self_type_matches_expected_vid(trait_ref, expected_vid)) - .and_then(|trait_ref| self.tcx.lang_items.fn_trait_kind(trait_ref.def_id())) - }) - .fold(None, |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur)))); - - (expected_sig, expected_kind) -} - -/// Given a projection like "::Result == Y", we can deduce -/// everything we need to know about a closure. -fn deduce_sig_from_projection(&self, - projection: &ty::PolyProjectionPredicate<'tcx>) - -> Option> -{ - let tcx = self.tcx; - - debug!("deduce_sig_from_projection({:?})", - projection); - - let trait_ref = projection.to_poly_trait_ref(); - - if tcx.lang_items.fn_trait_kind(trait_ref.def_id()).is_none() { - return None; + ty::TyInfer(ty::TyVar(vid)) => { + self.deduce_expectations_from_obligations(vid) + } + _ => { + (None, None) + } + } } - let arg_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 0); - let arg_param_ty = self.resolve_type_vars_if_possible(&arg_param_ty); - debug!("deduce_sig_from_projection: arg_param_ty {:?}", arg_param_ty); + fn deduce_expectations_from_obligations(&self, expected_vid: ty::TyVid) + -> (Option>, Option) + { + let fulfillment_cx = self.fulfillment_cx.borrow(); + // Here `expected_ty` is known to be a type inference variable. - let input_tys = match arg_param_ty.sty { - ty::TyTuple(tys) => tys.to_vec(), - _ => { return None; } - }; - debug!("deduce_sig_from_projection: input_tys {:?}", input_tys); + let expected_sig = + fulfillment_cx + .pending_obligations() + .iter() + .map(|obligation| &obligation.obligation) + .filter_map(|obligation| { + debug!("deduce_expectations_from_obligations: obligation.predicate={:?}", + obligation.predicate); - let ret_param_ty = projection.0.ty; - let ret_param_ty = self.resolve_type_vars_if_possible(&ret_param_ty); - debug!("deduce_sig_from_projection: ret_param_ty {:?}", ret_param_ty); + match obligation.predicate { + // Given a Projection predicate, we can potentially infer + // the complete signature. + ty::Predicate::Projection(ref proj_predicate) => { + let trait_ref = proj_predicate.to_poly_trait_ref(); + self.self_type_matches_expected_vid(trait_ref, expected_vid) + .and_then(|_| self.deduce_sig_from_projection(proj_predicate)) + } + _ => { + None + } + } + }) + .next(); - let fn_sig = ty::FnSig { - inputs: input_tys, - output: ty::FnConverging(ret_param_ty), - variadic: false - }; - debug!("deduce_sig_from_projection: fn_sig {:?}", fn_sig); + // Even if we can't infer the full signature, we may be able to + // infer the kind. This can occur if there is a trait-reference + // like `F : Fn`. Note that due to subtyping we could encounter + // many viable options, so pick the most restrictive. + let expected_kind = + fulfillment_cx + .pending_obligations() + .iter() + .map(|obligation| &obligation.obligation) + .filter_map(|obligation| { + let opt_trait_ref = match obligation.predicate { + ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref()), + ty::Predicate::Trait(ref data) => Some(data.to_poly_trait_ref()), + ty::Predicate::Equate(..) => None, + ty::Predicate::RegionOutlives(..) => None, + ty::Predicate::TypeOutlives(..) => None, + ty::Predicate::WellFormed(..) => None, + ty::Predicate::ObjectSafe(..) => None, + ty::Predicate::Rfc1592(..) => None, - Some(fn_sig) -} + // NB: This predicate is created by breaking down a + // `ClosureType: FnFoo()` predicate, where + // `ClosureType` represents some `TyClosure`. It can't + // possibly be referring to the current closure, + // because we haven't produced the `TyClosure` for + // this closure yet; this is exactly why the other + // code is looking for a self type of a unresolved + // inference variable. + ty::Predicate::ClosureKind(..) => None, + }; + opt_trait_ref + .and_then(|tr| self.self_type_matches_expected_vid(tr, expected_vid)) + .and_then(|tr| self.tcx.lang_items.fn_trait_kind(tr.def_id())) + }) + .fold(None, |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur)))); -fn self_type_matches_expected_vid(&self, - trait_ref: ty::PolyTraitRef<'tcx>, - expected_vid: ty::TyVid) - -> Option> -{ - let self_ty = self.shallow_resolve(trait_ref.self_ty()); - debug!("self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?})", - trait_ref, - self_ty); - match self_ty.sty { - ty::TyInfer(ty::TyVar(v)) if expected_vid == v => Some(trait_ref), - _ => None, + (expected_sig, expected_kind) + } + + /// Given a projection like "::Result == Y", we can deduce + /// everything we need to know about a closure. + fn deduce_sig_from_projection(&self, + projection: &ty::PolyProjectionPredicate<'tcx>) + -> Option> + { + let tcx = self.tcx; + + debug!("deduce_sig_from_projection({:?})", + projection); + + let trait_ref = projection.to_poly_trait_ref(); + + if tcx.lang_items.fn_trait_kind(trait_ref.def_id()).is_none() { + return None; + } + + let arg_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 0); + let arg_param_ty = self.resolve_type_vars_if_possible(&arg_param_ty); + debug!("deduce_sig_from_projection: arg_param_ty {:?}", arg_param_ty); + + let input_tys = match arg_param_ty.sty { + ty::TyTuple(tys) => tys.to_vec(), + _ => { return None; } + }; + debug!("deduce_sig_from_projection: input_tys {:?}", input_tys); + + let ret_param_ty = projection.0.ty; + let ret_param_ty = self.resolve_type_vars_if_possible(&ret_param_ty); + debug!("deduce_sig_from_projection: ret_param_ty {:?}", ret_param_ty); + + let fn_sig = ty::FnSig { + inputs: input_tys, + output: ty::FnConverging(ret_param_ty), + variadic: false + }; + debug!("deduce_sig_from_projection: fn_sig {:?}", fn_sig); + + Some(fn_sig) + } + + fn self_type_matches_expected_vid(&self, + trait_ref: ty::PolyTraitRef<'tcx>, + expected_vid: ty::TyVid) + -> Option> + { + let self_ty = self.shallow_resolve(trait_ref.self_ty()); + debug!("self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?})", + trait_ref, + self_ty); + match self_ty.sty { + ty::TyInfer(ty::TyVar(v)) if expected_vid == v => Some(trait_ref), + _ => None, + } } } -} diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 55786a03eeb..4861ab15e2c 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -618,167 +618,167 @@ fn apply<'a, 'b, 'gcx, 'tcx, E, I>(coerce: &mut Coerce<'a, 'gcx, 'tcx>, } impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { -/// Attempt to coerce an expression to a type, and return the -/// adjusted type of the expression, if successful. -/// Adjustments are only recorded if the coercion succeeded. -/// The expressions *must not* have any pre-existing adjustments. -pub fn try_coerce(&self, - expr: &hir::Expr, - target: Ty<'tcx>) - -> RelateResult<'tcx, Ty<'tcx>> { - let source = self.resolve_type_vars_with_obligations(self.expr_ty(expr)); - debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target); + /// Attempt to coerce an expression to a type, and return the + /// adjusted type of the expression, if successful. + /// Adjustments are only recorded if the coercion succeeded. + /// The expressions *must not* have any pre-existing adjustments. + pub fn try_coerce(&self, + expr: &hir::Expr, + target: Ty<'tcx>) + -> RelateResult<'tcx, Ty<'tcx>> { + let source = self.resolve_type_vars_with_obligations(self.expr_ty(expr)); + debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target); - let mut coerce = Coerce::new(self, TypeOrigin::ExprAssignable(expr.span)); - self.commit_if_ok(|_| { - let (ty, adjustment) = - apply(&mut coerce, &|| Some(expr), source, target)?; - if !adjustment.is_identity() { - debug!("Success, coerced with {:?}", adjustment); - assert!(!self.tables.borrow().adjustments.contains_key(&expr.id)); - self.write_adjustment(expr.id, adjustment); + let mut coerce = Coerce::new(self, TypeOrigin::ExprAssignable(expr.span)); + self.commit_if_ok(|_| { + let (ty, adjustment) = + apply(&mut coerce, &|| Some(expr), source, target)?; + if !adjustment.is_identity() { + debug!("Success, coerced with {:?}", adjustment); + assert!(!self.tables.borrow().adjustments.contains_key(&expr.id)); + self.write_adjustment(expr.id, adjustment); + } + Ok(ty) + }) + } + + /// Given some expressions, their known unified type and another expression, + /// tries to unify the types, potentially inserting coercions on any of the + /// provided expressions and returns their LUB (aka "common supertype"). + pub fn try_find_coercion_lub<'b, E, I>(&self, + origin: TypeOrigin, + exprs: E, + prev_ty: Ty<'tcx>, + new: &'b hir::Expr) + -> RelateResult<'tcx, Ty<'tcx>> + // FIXME(eddyb) use copyable iterators when that becomes ergonomic. + where E: Fn() -> I, + I: IntoIterator { + + let prev_ty = self.resolve_type_vars_with_obligations(prev_ty); + let new_ty = self.resolve_type_vars_with_obligations(self.expr_ty(new)); + debug!("coercion::try_find_lub({:?}, {:?})", prev_ty, new_ty); + + let trace = TypeTrace::types(origin, true, prev_ty, new_ty); + + // Special-case that coercion alone cannot handle: + // Two function item types of differing IDs or Substs. + match (&prev_ty.sty, &new_ty.sty) { + (&ty::TyFnDef(a_def_id, a_substs, a_fty), + &ty::TyFnDef(b_def_id, b_substs, b_fty)) => { + // The signature must always match. + let fty = self.lub(true, trace.clone(), &a_fty, &b_fty) + .map(|InferOk { value, obligations }| { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()); + value + })?; + + if a_def_id == b_def_id { + // Same function, maybe the parameters match. + let substs = self.commit_if_ok(|_| { + self.lub(true, trace.clone(), &a_substs, &b_substs) + .map(|InferOk { value, obligations }| { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()); + value + }) + }); + + if let Ok(substs) = substs { + // We have a LUB of prev_ty and new_ty, just return it. + return Ok(self.tcx.mk_fn_def(a_def_id, substs, fty)); + } + } + + // Reify both sides and return the reified fn pointer type. + for expr in exprs().into_iter().chain(Some(new)) { + // No adjustments can produce a fn item, so this should never trip. + assert!(!self.tables.borrow().adjustments.contains_key(&expr.id)); + self.write_adjustment(expr.id, AdjustReifyFnPointer); + } + return Ok(self.tcx.mk_fn_ptr(fty)); + } + _ => {} } - Ok(ty) - }) -} -/// Given some expressions, their known unified type and another expression, -/// tries to unify the types, potentially inserting coercions on any of the -/// provided expressions and returns their LUB (aka "common supertype"). -pub fn try_find_coercion_lub<'b, E, I>(&self, - origin: TypeOrigin, - exprs: E, - prev_ty: Ty<'tcx>, - new: &'b hir::Expr) - -> RelateResult<'tcx, Ty<'tcx>> - // FIXME(eddyb) use copyable iterators when that becomes ergonomic. - where E: Fn() -> I, - I: IntoIterator { + let mut coerce = Coerce::new(self, origin); + coerce.use_lub = true; - let prev_ty = self.resolve_type_vars_with_obligations(prev_ty); - let new_ty = self.resolve_type_vars_with_obligations(self.expr_ty(new)); - debug!("coercion::try_find_lub({:?}, {:?})", prev_ty, new_ty); + // First try to coerce the new expression to the type of the previous ones, + // but only if the new expression has no coercion already applied to it. + let mut first_error = None; + if !self.tables.borrow().adjustments.contains_key(&new.id) { + let result = self.commit_if_ok(|_| { + apply(&mut coerce, &|| Some(new), new_ty, prev_ty) + }); + match result { + Ok((ty, adjustment)) => { + if !adjustment.is_identity() { + self.write_adjustment(new.id, adjustment); + } + return Ok(ty); + } + Err(e) => first_error = Some(e) + } + } - let trace = TypeTrace::types(origin, true, prev_ty, new_ty); + // Then try to coerce the previous expressions to the type of the new one. + // This requires ensuring there are no coercions applied to *any* of the + // previous expressions, other than noop reborrows (ignoring lifetimes). + for expr in exprs() { + let noop = match self.tables.borrow().adjustments.get(&expr.id) { + Some(&AdjustDerefRef(AutoDerefRef { + autoderefs: 1, + autoref: Some(AutoPtr(_, mutbl_adj)), + unsize: None + })) => match self.expr_ty(expr).sty { + ty::TyRef(_, mt_orig) => { + // Reborrow that we can safely ignore. + mutbl_adj == mt_orig.mutbl + } + _ => false + }, + Some(_) => false, + None => true + }; - // Special-case that coercion alone cannot handle: - // Two function item types of differing IDs or Substs. - match (&prev_ty.sty, &new_ty.sty) { - (&ty::TyFnDef(a_def_id, a_substs, a_fty), - &ty::TyFnDef(b_def_id, b_substs, b_fty)) => { - // The signature must always match. - let fty = self.lub(true, trace.clone(), &a_fty, &b_fty) - .map(|InferOk { value, obligations }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - value - })?; - - if a_def_id == b_def_id { - // Same function, maybe the parameters match. - let substs = self.commit_if_ok(|_| { - self.lub(true, trace.clone(), &a_substs, &b_substs) + if !noop { + return self.commit_if_ok(|_| { + self.lub(true, trace.clone(), &prev_ty, &new_ty) .map(|InferOk { value, obligations }| { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()); value }) }); + } + } - if let Ok(substs) = substs { - // We have a LUB of prev_ty and new_ty, just return it. - return Ok(self.tcx.mk_fn_def(a_def_id, substs, fty)); + match self.commit_if_ok(|_| apply(&mut coerce, &exprs, prev_ty, new_ty)) { + Err(_) => { + // Avoid giving strange errors on failed attempts. + if let Some(e) = first_error { + Err(e) + } else { + self.commit_if_ok(|_| { + self.lub(true, trace, &prev_ty, &new_ty) + .map(|InferOk { value, obligations }| { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()); + value + }) + }) } } - - // Reify both sides and return the reified fn pointer type. - for expr in exprs().into_iter().chain(Some(new)) { - // No adjustments can produce a fn item, so this should never trip. - assert!(!self.tables.borrow().adjustments.contains_key(&expr.id)); - self.write_adjustment(expr.id, AdjustReifyFnPointer); - } - return Ok(self.tcx.mk_fn_ptr(fty)); - } - _ => {} - } - - let mut coerce = Coerce::new(self, origin); - coerce.use_lub = true; - - // First try to coerce the new expression to the type of the previous ones, - // but only if the new expression has no coercion already applied to it. - let mut first_error = None; - if !self.tables.borrow().adjustments.contains_key(&new.id) { - let result = self.commit_if_ok(|_| { - apply(&mut coerce, &|| Some(new), new_ty, prev_ty) - }); - match result { Ok((ty, adjustment)) => { if !adjustment.is_identity() { - self.write_adjustment(new.id, adjustment); + for expr in exprs() { + self.write_adjustment(expr.id, adjustment); + } } - return Ok(ty); + Ok(ty) } - Err(e) => first_error = Some(e) - } - } - - // Then try to coerce the previous expressions to the type of the new one. - // This requires ensuring there are no coercions applied to *any* of the - // previous expressions, other than noop reborrows (ignoring lifetimes). - for expr in exprs() { - let noop = match self.tables.borrow().adjustments.get(&expr.id) { - Some(&AdjustDerefRef(AutoDerefRef { - autoderefs: 1, - autoref: Some(AutoPtr(_, mutbl_adj)), - unsize: None - })) => match self.expr_ty(expr).sty { - ty::TyRef(_, mt_orig) => { - // Reborrow that we can safely ignore. - mutbl_adj == mt_orig.mutbl - } - _ => false - }, - Some(_) => false, - None => true - }; - - if !noop { - return self.commit_if_ok(|_| { - self.lub(true, trace.clone(), &prev_ty, &new_ty) - .map(|InferOk { value, obligations }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - value - }) - }); - } - } - - match self.commit_if_ok(|_| apply(&mut coerce, &exprs, prev_ty, new_ty)) { - Err(_) => { - // Avoid giving strange errors on failed attempts. - if let Some(e) = first_error { - Err(e) - } else { - self.commit_if_ok(|_| { - self.lub(true, trace, &prev_ty, &new_ty) - .map(|InferOk { value, obligations }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - value - }) - }) - } - } - Ok((ty, adjustment)) => { - if !adjustment.is_identity() { - for expr in exprs() { - self.write_adjustment(expr.id, adjustment); - } - } - Ok(ty) } } } -} diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 065425c86c7..7c8eb62b0e7 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -17,53 +17,53 @@ use syntax::codemap::Span; use rustc::hir; impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { -// Requires that the two types unify, and prints an error message if -// they don't. -pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { - let origin = TypeOrigin::Misc(sp); - match self.sub_types(false, origin, actual, expected) { - Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - }, - Err(e) => { - self.report_mismatched_types(origin, expected, actual, e); + // Requires that the two types unify, and prints an error message if + // they don't. + pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { + let origin = TypeOrigin::Misc(sp); + match self.sub_types(false, origin, actual, expected) { + Ok(InferOk { obligations, .. }) => { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()); + }, + Err(e) => { + self.report_mismatched_types(origin, expected, actual, e); + } + } + } + + pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { + let origin = TypeOrigin::Misc(sp); + match self.eq_types(false, origin, actual, expected) { + Ok(InferOk { obligations, .. }) => { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()); + }, + Err(e) => { + self.report_mismatched_types(origin, expected, actual, e); + } + } + } + + // Checks that the type of `expr` can be coerced to `expected`. + pub fn demand_coerce(&self, expr: &hir::Expr, expected: Ty<'tcx>) { + let expected = self.resolve_type_vars_with_obligations(expected); + if let Err(e) = self.try_coerce(expr, expected) { + let origin = TypeOrigin::Misc(expr.span); + let expr_ty = self.resolve_type_vars_with_obligations(self.expr_ty(expr)); + self.report_mismatched_types(origin, expected, expr_ty, e); + } + } + + pub fn require_same_types(&self, span: Span, t1: Ty<'tcx>, t2: Ty<'tcx>, msg: &str) + -> bool { + if let Err(err) = self.eq_types(false, TypeOrigin::Misc(span), t1, t2) { + let found_ty = self.resolve_type_vars_if_possible(&t1); + let expected_ty = self.resolve_type_vars_if_possible(&t2); + ::emit_type_err(self.tcx, span, found_ty, expected_ty, &err, msg); + false + } else { + true } } } - -pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { - let origin = TypeOrigin::Misc(sp); - match self.eq_types(false, origin, actual, expected) { - Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - }, - Err(e) => { - self.report_mismatched_types(origin, expected, actual, e); - } - } -} - -// Checks that the type of `expr` can be coerced to `expected`. -pub fn demand_coerce(&self, expr: &hir::Expr, expected: Ty<'tcx>) { - let expected = self.resolve_type_vars_with_obligations(expected); - if let Err(e) = self.try_coerce(expr, expected) { - let origin = TypeOrigin::Misc(expr.span); - let expr_ty = self.resolve_type_vars_with_obligations(self.expr_ty(expr)); - self.report_mismatched_types(origin, expected, expr_ty, e); - } -} - -pub fn require_same_types(&self, span: Span, t1: Ty<'tcx>, t2: Ty<'tcx>, msg: &str) - -> bool { - if let Err(err) = self.eq_types(false, TypeOrigin::Misc(span), t1, t2) { - let found_ty = self.resolve_type_vars_if_possible(&t1); - let expected_ty = self.resolve_type_vars_if_possible(&t2); - ::emit_type_err(self.tcx, span, found_ty, expected_ty, &err, msg); - false - } else { - true - } -} -} diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 3360f9dab78..6faf6f415c2 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -53,23 +53,23 @@ struct InstantiatedMethodSig<'tcx> { } impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { -pub fn confirm_method(&self, - span: Span, - self_expr: &'gcx hir::Expr, - call_expr: &'gcx hir::Expr, - unadjusted_self_ty: Ty<'tcx>, - pick: probe::Pick<'tcx>, - supplied_method_types: Vec>) - -> ty::MethodCallee<'tcx> -{ - debug!("confirm(unadjusted_self_ty={:?}, pick={:?}, supplied_method_types={:?})", - unadjusted_self_ty, - pick, - supplied_method_types); + pub fn confirm_method(&self, + span: Span, + self_expr: &'gcx hir::Expr, + call_expr: &'gcx hir::Expr, + unadjusted_self_ty: Ty<'tcx>, + pick: probe::Pick<'tcx>, + supplied_method_types: Vec>) + -> ty::MethodCallee<'tcx> + { + debug!("confirm(unadjusted_self_ty={:?}, pick={:?}, supplied_method_types={:?})", + unadjusted_self_ty, + pick, + supplied_method_types); - let mut confirm_cx = ConfirmContext::new(self, span, self_expr, call_expr); - confirm_cx.confirm(unadjusted_self_ty, pick, supplied_method_types) -} + let mut confirm_cx = ConfirmContext::new(self, span, self_expr, call_expr); + confirm_cx.confirm(unadjusted_self_ty, pick, supplied_method_types) + } } impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index f30abbaba0e..f27ae181f77 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -79,311 +79,314 @@ pub enum CandidateSource { } impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { -/// Determines whether the type `self_ty` supports a method name `method_name` or not. -pub fn method_exists(&self, - span: Span, - method_name: ast::Name, - self_ty: ty::Ty<'tcx>, - call_expr_id: ast::NodeId) - -> bool -{ - let mode = probe::Mode::MethodCall; - match self.probe_method(span, mode, method_name, self_ty, call_expr_id) { - Ok(..) => true, - Err(NoMatch(..)) => false, - Err(Ambiguity(..)) => true, - Err(ClosureAmbiguity(..)) => true, - Err(PrivateMatch(..)) => true, - } -} - -/// Performs method lookup. If lookup is successful, it will return the callee and store an -/// appropriate adjustment for the self-expr. In some cases it may report an error (e.g., invoking -/// the `drop` method). -/// -/// # Arguments -/// -/// Given a method call like `foo.bar::(...)`: -/// -/// * `fcx`: the surrounding `FnCtxt` (!) -/// * `span`: the span for the method call -/// * `method_name`: the name of the method being called (`bar`) -/// * `self_ty`: the (unadjusted) type of the self expression (`foo`) -/// * `supplied_method_types`: the explicit method type parameters, if any (`T1..Tn`) -/// * `self_expr`: the self expression (`foo`) -pub fn lookup_method(&self, - span: Span, - method_name: ast::Name, - self_ty: ty::Ty<'tcx>, - supplied_method_types: Vec>, - call_expr: &'gcx hir::Expr, - self_expr: &'gcx hir::Expr) - -> Result, MethodError<'tcx>> -{ - debug!("lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})", - method_name, - self_ty, - call_expr, - self_expr); - - let mode = probe::Mode::MethodCall; - let self_ty = self.resolve_type_vars_if_possible(&self_ty); - let pick = self.probe_method(span, mode, method_name, self_ty, call_expr.id)?; - - if let Some(import_id) = pick.import_id { - self.tcx.used_trait_imports.borrow_mut().insert(import_id); - } - - Ok(self.confirm_method(span, self_expr, call_expr, self_ty, pick, supplied_method_types)) -} - -pub fn lookup_method_in_trait(&self, - span: Span, - self_expr: Option<&hir::Expr>, - m_name: ast::Name, - trait_def_id: DefId, - self_ty: ty::Ty<'tcx>, - opt_input_types: Option>>) - -> Option> -{ - self.lookup_method_in_trait_adjusted(span, self_expr, m_name, trait_def_id, - 0, false, self_ty, opt_input_types) -} - -/// `lookup_in_trait_adjusted` is used for overloaded operators. It does a very narrow slice of -/// what the normal probe/confirm path does. In particular, it doesn't really do any probing: it -/// simply constructs an obligation for a particular trait with the given self-type and checks -/// whether that trait is implemented. -/// -/// FIXME(#18741) -- It seems likely that we can consolidate some of this code with the other -/// method-lookup code. In particular, autoderef on index is basically identical to autoderef with -/// normal probes, except that the test also looks for built-in indexing. Also, the second half of -/// this method is basically the same as confirmation. -pub fn lookup_method_in_trait_adjusted(&self, - span: Span, - self_expr: Option<&hir::Expr>, - m_name: ast::Name, - trait_def_id: DefId, - autoderefs: usize, - unsize: bool, - self_ty: ty::Ty<'tcx>, - opt_input_types: Option>>) - -> Option> -{ - debug!("lookup_in_trait_adjusted(self_ty={:?}, self_expr={:?}, m_name={}, trait_def_id={:?})", - self_ty, - self_expr, - m_name, - trait_def_id); - - let trait_def = self.tcx.lookup_trait_def(trait_def_id); - - let type_parameter_defs = trait_def.generics.types.get_slice(subst::TypeSpace); - let expected_number_of_input_types = type_parameter_defs.len(); - - assert_eq!(trait_def.generics.types.len(subst::FnSpace), 0); - assert!(trait_def.generics.regions.is_empty()); - - // Construct a trait-reference `self_ty : Trait` - let mut substs = subst::Substs::new_trait(Vec::new(), Vec::new(), self_ty); - - match opt_input_types { - Some(input_types) => { - assert_eq!(expected_number_of_input_types, input_types.len()); - substs.types.replace(subst::ParamSpace::TypeSpace, input_types); - } - - None => { - self.type_vars_for_defs( - span, - subst::ParamSpace::TypeSpace, - &mut substs, - type_parameter_defs); + /// Determines whether the type `self_ty` supports a method name `method_name` or not. + pub fn method_exists(&self, + span: Span, + method_name: ast::Name, + self_ty: ty::Ty<'tcx>, + call_expr_id: ast::NodeId) + -> bool + { + let mode = probe::Mode::MethodCall; + match self.probe_method(span, mode, method_name, self_ty, call_expr_id) { + Ok(..) => true, + Err(NoMatch(..)) => false, + Err(Ambiguity(..)) => true, + Err(ClosureAmbiguity(..)) => true, + Err(PrivateMatch(..)) => true, } } - let trait_ref = ty::TraitRef::new(trait_def_id, self.tcx.mk_substs(substs)); + /// Performs method lookup. If lookup is successful, it will return the callee + /// and store an appropriate adjustment for the self-expr. In some cases it may + /// report an error (e.g., invoking the `drop` method). + /// + /// # Arguments + /// + /// Given a method call like `foo.bar::(...)`: + /// + /// * `fcx`: the surrounding `FnCtxt` (!) + /// * `span`: the span for the method call + /// * `method_name`: the name of the method being called (`bar`) + /// * `self_ty`: the (unadjusted) type of the self expression (`foo`) + /// * `supplied_method_types`: the explicit method type parameters, if any (`T1..Tn`) + /// * `self_expr`: the self expression (`foo`) + pub fn lookup_method(&self, + span: Span, + method_name: ast::Name, + self_ty: ty::Ty<'tcx>, + supplied_method_types: Vec>, + call_expr: &'gcx hir::Expr, + self_expr: &'gcx hir::Expr) + -> Result, MethodError<'tcx>> + { + debug!("lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})", + method_name, + self_ty, + call_expr, + self_expr); - // Construct an obligation - let poly_trait_ref = trait_ref.to_poly_trait_ref(); - let obligation = traits::Obligation::misc(span, - self.body_id, - poly_trait_ref.to_predicate()); + let mode = probe::Mode::MethodCall; + let self_ty = self.resolve_type_vars_if_possible(&self_ty); + let pick = self.probe_method(span, mode, method_name, self_ty, call_expr.id)?; - // Now we want to know if this can be matched - let mut selcx = traits::SelectionContext::new(self); - if !selcx.evaluate_obligation(&obligation) { - debug!("--> Cannot match obligation"); - return None; // Cannot be matched, no such method resolution is possible. + if let Some(import_id) = pick.import_id { + self.tcx.used_trait_imports.borrow_mut().insert(import_id); + } + + Ok(self.confirm_method(span, self_expr, call_expr, self_ty, pick, supplied_method_types)) } - // Trait must have a method named `m_name` and it should not have - // type parameters or early-bound regions. - let tcx = self.tcx; - let method_item = self.trait_item(trait_def_id, m_name).unwrap(); - let method_ty = method_item.as_opt_method().unwrap(); - assert_eq!(method_ty.generics.types.len(subst::FnSpace), 0); - assert_eq!(method_ty.generics.regions.len(subst::FnSpace), 0); + pub fn lookup_method_in_trait(&self, + span: Span, + self_expr: Option<&hir::Expr>, + m_name: ast::Name, + trait_def_id: DefId, + self_ty: ty::Ty<'tcx>, + opt_input_types: Option>>) + -> Option> + { + self.lookup_method_in_trait_adjusted(span, self_expr, m_name, trait_def_id, + 0, false, self_ty, opt_input_types) + } - debug!("lookup_in_trait_adjusted: method_item={:?} method_ty={:?}", - method_item, method_ty); + /// `lookup_in_trait_adjusted` is used for overloaded operators. + /// It does a very narrow slice of what the normal probe/confirm path does. + /// In particular, it doesn't really do any probing: it simply constructs + /// an obligation for aparticular trait with the given self-type and checks + /// whether that trait is implemented. + /// + /// FIXME(#18741) -- It seems likely that we can consolidate some of this + /// code with the other method-lookup code. In particular, autoderef on + /// index is basically identical to autoderef with normal probes, except + /// that the test also looks for built-in indexing. Also, the second half of + /// this method is basically the same as confirmation. + pub fn lookup_method_in_trait_adjusted(&self, + span: Span, + self_expr: Option<&hir::Expr>, + m_name: ast::Name, + trait_def_id: DefId, + autoderefs: usize, + unsize: bool, + self_ty: ty::Ty<'tcx>, + opt_input_types: Option>>) + -> Option> + { + debug!("lookup_in_trait_adjusted(self_ty={:?}, self_expr={:?}, \ + m_name={}, trait_def_id={:?})", + self_ty, + self_expr, + m_name, + trait_def_id); - // Instantiate late-bound regions and substitute the trait - // parameters into the method type to get the actual method type. - // - // NB: Instantiate late-bound regions first so that - // `instantiate_type_scheme` can normalize associated types that - // may reference those regions. - let fn_sig = self.replace_late_bound_regions_with_fresh_var(span, - infer::FnCall, - &method_ty.fty.sig).0; - let fn_sig = self.instantiate_type_scheme(span, trait_ref.substs, &fn_sig); - let transformed_self_ty = fn_sig.inputs[0]; - let def_id = method_item.def_id(); - let fty = tcx.mk_fn_def(def_id, trait_ref.substs, - tcx.mk_bare_fn(ty::BareFnTy { - sig: ty::Binder(fn_sig), - unsafety: method_ty.fty.unsafety, - abi: method_ty.fty.abi.clone(), - })); + let trait_def = self.tcx.lookup_trait_def(trait_def_id); - debug!("lookup_in_trait_adjusted: matched method fty={:?} obligation={:?}", - fty, - obligation); + let type_parameter_defs = trait_def.generics.types.get_slice(subst::TypeSpace); + let expected_number_of_input_types = type_parameter_defs.len(); - // Register obligations for the parameters. This will include the - // `Self` parameter, which in turn has a bound of the main trait, - // so this also effectively registers `obligation` as well. (We - // used to register `obligation` explicitly, but that resulted in - // double error messages being reported.) - // - // Note that as the method comes from a trait, it should not have - // any late-bound regions appearing in its bounds. - let method_bounds = self.instantiate_bounds(span, trait_ref.substs, &method_ty.predicates); - assert!(!method_bounds.has_escaping_regions()); - self.add_obligations_for_parameters( - traits::ObligationCause::misc(span, self.body_id), - &method_bounds); + assert_eq!(trait_def.generics.types.len(subst::FnSpace), 0); + assert!(trait_def.generics.regions.is_empty()); - // Also register an obligation for the method type being well-formed. - self.register_wf_obligation(fty, span, traits::MiscObligation); + // Construct a trait-reference `self_ty : Trait` + let mut substs = subst::Substs::new_trait(Vec::new(), Vec::new(), self_ty); - // FIXME(#18653) -- Try to resolve obligations, giving us more - // typing information, which can sometimes be needed to avoid - // pathological region inference failures. - self.select_obligations_where_possible(); + match opt_input_types { + Some(input_types) => { + assert_eq!(expected_number_of_input_types, input_types.len()); + substs.types.replace(subst::ParamSpace::TypeSpace, input_types); + } - // Insert any adjustments needed (always an autoref of some mutability). - match self_expr { - None => { } + None => { + self.type_vars_for_defs( + span, + subst::ParamSpace::TypeSpace, + &mut substs, + type_parameter_defs); + } + } - Some(self_expr) => { - debug!("lookup_in_trait_adjusted: inserting adjustment if needed \ - (self-id={}, autoderefs={}, unsize={}, explicit_self={:?})", - self_expr.id, autoderefs, unsize, - method_ty.explicit_self); + let trait_ref = ty::TraitRef::new(trait_def_id, self.tcx.mk_substs(substs)); - match method_ty.explicit_self { - ty::ExplicitSelfCategory::ByValue => { - // Trait method is fn(self), no transformation needed. - assert!(!unsize); - self.write_autoderef_adjustment(self_expr.id, autoderefs); - } + // Construct an obligation + let poly_trait_ref = trait_ref.to_poly_trait_ref(); + let obligation = traits::Obligation::misc(span, + self.body_id, + poly_trait_ref.to_predicate()); - ty::ExplicitSelfCategory::ByReference(..) => { - // Trait method is fn(&self) or fn(&mut self), need an - // autoref. Pull the region etc out of the type of first argument. - match transformed_self_ty.sty { - ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ }) => { - self.write_adjustment(self_expr.id, - AdjustDerefRef(AutoDerefRef { - autoderefs: autoderefs, - autoref: Some(AutoPtr(region, mutbl)), - unsize: if unsize { - Some(transformed_self_ty) - } else { - None - } - })); - } + // Now we want to know if this can be matched + let mut selcx = traits::SelectionContext::new(self); + if !selcx.evaluate_obligation(&obligation) { + debug!("--> Cannot match obligation"); + return None; // Cannot be matched, no such method resolution is possible. + } - _ => { - span_bug!( - span, - "trait method is &self but first arg is: {}", - transformed_self_ty); + // Trait must have a method named `m_name` and it should not have + // type parameters or early-bound regions. + let tcx = self.tcx; + let method_item = self.trait_item(trait_def_id, m_name).unwrap(); + let method_ty = method_item.as_opt_method().unwrap(); + assert_eq!(method_ty.generics.types.len(subst::FnSpace), 0); + assert_eq!(method_ty.generics.regions.len(subst::FnSpace), 0); + + debug!("lookup_in_trait_adjusted: method_item={:?} method_ty={:?}", + method_item, method_ty); + + // Instantiate late-bound regions and substitute the trait + // parameters into the method type to get the actual method type. + // + // NB: Instantiate late-bound regions first so that + // `instantiate_type_scheme` can normalize associated types that + // may reference those regions. + let fn_sig = self.replace_late_bound_regions_with_fresh_var(span, + infer::FnCall, + &method_ty.fty.sig).0; + let fn_sig = self.instantiate_type_scheme(span, trait_ref.substs, &fn_sig); + let transformed_self_ty = fn_sig.inputs[0]; + let def_id = method_item.def_id(); + let fty = tcx.mk_fn_def(def_id, trait_ref.substs, + tcx.mk_bare_fn(ty::BareFnTy { + sig: ty::Binder(fn_sig), + unsafety: method_ty.fty.unsafety, + abi: method_ty.fty.abi.clone(), + })); + + debug!("lookup_in_trait_adjusted: matched method fty={:?} obligation={:?}", + fty, + obligation); + + // Register obligations for the parameters. This will include the + // `Self` parameter, which in turn has a bound of the main trait, + // so this also effectively registers `obligation` as well. (We + // used to register `obligation` explicitly, but that resulted in + // double error messages being reported.) + // + // Note that as the method comes from a trait, it should not have + // any late-bound regions appearing in its bounds. + let method_bounds = self.instantiate_bounds(span, trait_ref.substs, &method_ty.predicates); + assert!(!method_bounds.has_escaping_regions()); + self.add_obligations_for_parameters( + traits::ObligationCause::misc(span, self.body_id), + &method_bounds); + + // Also register an obligation for the method type being well-formed. + self.register_wf_obligation(fty, span, traits::MiscObligation); + + // FIXME(#18653) -- Try to resolve obligations, giving us more + // typing information, which can sometimes be needed to avoid + // pathological region inference failures. + self.select_obligations_where_possible(); + + // Insert any adjustments needed (always an autoref of some mutability). + match self_expr { + None => { } + + Some(self_expr) => { + debug!("lookup_in_trait_adjusted: inserting adjustment if needed \ + (self-id={}, autoderefs={}, unsize={}, explicit_self={:?})", + self_expr.id, autoderefs, unsize, + method_ty.explicit_self); + + match method_ty.explicit_self { + ty::ExplicitSelfCategory::ByValue => { + // Trait method is fn(self), no transformation needed. + assert!(!unsize); + self.write_autoderef_adjustment(self_expr.id, autoderefs); + } + + ty::ExplicitSelfCategory::ByReference(..) => { + // Trait method is fn(&self) or fn(&mut self), need an + // autoref. Pull the region etc out of the type of first argument. + match transformed_self_ty.sty { + ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ }) => { + self.write_adjustment(self_expr.id, + AdjustDerefRef(AutoDerefRef { + autoderefs: autoderefs, + autoref: Some(AutoPtr(region, mutbl)), + unsize: if unsize { + Some(transformed_self_ty) + } else { + None + } + })); + } + + _ => { + span_bug!( + span, + "trait method is &self but first arg is: {}", + transformed_self_ty); + } } } - } - _ => { - span_bug!( - span, - "unexpected explicit self type in operator method: {:?}", - method_ty.explicit_self); + _ => { + span_bug!( + span, + "unexpected explicit self type in operator method: {:?}", + method_ty.explicit_self); + } } } } + + let callee = ty::MethodCallee { + def_id: def_id, + ty: fty, + substs: trait_ref.substs + }; + + debug!("callee = {:?}", callee); + + Some(callee) } - let callee = ty::MethodCallee { - def_id: def_id, - ty: fty, - substs: trait_ref.substs - }; + pub fn resolve_ufcs(&self, + span: Span, + method_name: ast::Name, + self_ty: ty::Ty<'tcx>, + expr_id: ast::NodeId) + -> Result> + { + let mode = probe::Mode::Path; + let pick = self.probe_method(span, mode, method_name, self_ty, expr_id)?; - debug!("callee = {:?}", callee); - - Some(callee) -} - -pub fn resolve_ufcs(&self, - span: Span, - method_name: ast::Name, - self_ty: ty::Ty<'tcx>, - expr_id: ast::NodeId) - -> Result> -{ - let mode = probe::Mode::Path; - let pick = self.probe_method(span, mode, method_name, self_ty, expr_id)?; - - if let Some(import_id) = pick.import_id { - self.tcx.used_trait_imports.borrow_mut().insert(import_id); - } - - let def = pick.item.def(); - if let probe::InherentImplPick = pick.kind { - if !pick.item.vis().is_accessible_from(self.body_id, &self.tcx.map) { - let msg = format!("{} `{}` is private", def.kind_name(), &method_name.as_str()); - self.tcx.sess.span_err(span, &msg); + if let Some(import_id) = pick.import_id { + self.tcx.used_trait_imports.borrow_mut().insert(import_id); } + + let def = pick.item.def(); + if let probe::InherentImplPick = pick.kind { + if !pick.item.vis().is_accessible_from(self.body_id, &self.tcx.map) { + let msg = format!("{} `{}` is private", def.kind_name(), &method_name.as_str()); + self.tcx.sess.span_err(span, &msg); + } + } + Ok(def) } - Ok(def) -} -/// Find item with name `item_name` defined in `trait_def_id` -/// and return it, or `None`, if no such item. -pub fn trait_item(&self, - trait_def_id: DefId, - item_name: ast::Name) - -> Option> -{ - let trait_items = self.tcx.trait_items(trait_def_id); - trait_items.iter() - .find(|item| item.name() == item_name) - .cloned() -} + /// Find item with name `item_name` defined in `trait_def_id` + /// and return it, or `None`, if no such item. + pub fn trait_item(&self, + trait_def_id: DefId, + item_name: ast::Name) + -> Option> + { + let trait_items = self.tcx.trait_items(trait_def_id); + trait_items.iter() + .find(|item| item.name() == item_name) + .cloned() + } -pub fn impl_item(&self, - impl_def_id: DefId, - item_name: ast::Name) - -> Option> -{ - let impl_items = self.tcx.impl_items.borrow(); - let impl_items = impl_items.get(&impl_def_id).unwrap(); - impl_items - .iter() - .map(|&did| self.tcx.impl_or_trait_item(did.def_id())) - .find(|m| m.name() == item_name) -} + pub fn impl_item(&self, + impl_def_id: DefId, + item_name: ast::Name) + -> Option> + { + let impl_items = self.tcx.impl_items.borrow(); + let impl_items = impl_items.get(&impl_def_id).unwrap(); + impl_items + .iter() + .map(|&did| self.tcx.impl_or_trait_item(did.def_id())) + .find(|m| m.name() == item_name) + } } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 8ce92892e9a..08c04122517 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -137,108 +137,108 @@ pub enum Mode { } impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { -pub fn probe_method(&self, - span: Span, - mode: Mode, - item_name: ast::Name, - self_ty: Ty<'tcx>, - scope_expr_id: ast::NodeId) - -> PickResult<'tcx> -{ - debug!("probe(self_ty={:?}, item_name={}, scope_expr_id={})", - self_ty, - item_name, - scope_expr_id); + pub fn probe_method(&self, + span: Span, + mode: Mode, + item_name: ast::Name, + self_ty: Ty<'tcx>, + scope_expr_id: ast::NodeId) + -> PickResult<'tcx> + { + debug!("probe(self_ty={:?}, item_name={}, scope_expr_id={})", + self_ty, + item_name, + scope_expr_id); - // FIXME(#18741) -- right now, creating the steps involves evaluating the - // `*` operator, which registers obligations that then escape into - // the global fulfillment context and thus has global - // side-effects. This is a bit of a pain to refactor. So just let - // it ride, although it's really not great, and in fact could I - // think cause spurious errors. Really though this part should - // take place in the `self.probe` below. - let steps = if mode == Mode::MethodCall { - match self.create_steps(span, self_ty) { - Some(steps) => steps, - None =>return Err(MethodError::NoMatch(NoMatchData::new(Vec::new(), Vec::new(), - Vec::new(), mode))), - } - } else { - vec![CandidateStep { - self_ty: self_ty, - autoderefs: 0, - unsize: false - }] - }; - - // Create a list of simplified self types, if we can. - let mut simplified_steps = Vec::new(); - for step in &steps { - match ty::fast_reject::simplify_type(self.tcx, step.self_ty, true) { - None => { break; } - Some(simplified_type) => { simplified_steps.push(simplified_type); } - } - } - let opt_simplified_steps = - if simplified_steps.len() < steps.len() { - None // failed to convert at least one of the steps + // FIXME(#18741) -- right now, creating the steps involves evaluating the + // `*` operator, which registers obligations that then escape into + // the global fulfillment context and thus has global + // side-effects. This is a bit of a pain to refactor. So just let + // it ride, although it's really not great, and in fact could I + // think cause spurious errors. Really though this part should + // take place in the `self.probe` below. + let steps = if mode == Mode::MethodCall { + match self.create_steps(span, self_ty) { + Some(steps) => steps, + None =>return Err(MethodError::NoMatch(NoMatchData::new(Vec::new(), Vec::new(), + Vec::new(), mode))), + } } else { - Some(simplified_steps) + vec![CandidateStep { + self_ty: self_ty, + autoderefs: 0, + unsize: false + }] }; - debug!("ProbeContext: steps for self_ty={:?} are {:?}", - self_ty, - steps); - - // this creates one big transaction so that all type variables etc - // that we create during the probe process are removed later - self.probe(|_| { - let mut probe_cx = ProbeContext::new(self, - span, - mode, - item_name, - steps, - opt_simplified_steps); - probe_cx.assemble_inherent_candidates(); - probe_cx.assemble_extension_candidates_for_traits_in_scope(scope_expr_id)?; - probe_cx.pick() - }) -} - -fn create_steps(&self, - span: Span, - self_ty: Ty<'tcx>) - -> Option>> { - let mut steps = Vec::new(); - - let (final_ty, dereferences, _) = self.autoderef(span, - self_ty, - || None, - UnresolvedTypeAction::Error, - NoPreference, - |t, d| { - steps.push(CandidateStep { - self_ty: t, - autoderefs: d, - unsize: false - }); - None::<()> // keep iterating until we can't anymore - }); - - match final_ty.sty { - ty::TyArray(elem_ty, _) => { - steps.push(CandidateStep { - self_ty: self.tcx.mk_slice(elem_ty), - autoderefs: dereferences, - unsize: true - }); + // Create a list of simplified self types, if we can. + let mut simplified_steps = Vec::new(); + for step in &steps { + match ty::fast_reject::simplify_type(self.tcx, step.self_ty, true) { + None => { break; } + Some(simplified_type) => { simplified_steps.push(simplified_type); } + } } - ty::TyError => return None, - _ => (), + let opt_simplified_steps = + if simplified_steps.len() < steps.len() { + None // failed to convert at least one of the steps + } else { + Some(simplified_steps) + }; + + debug!("ProbeContext: steps for self_ty={:?} are {:?}", + self_ty, + steps); + + // this creates one big transaction so that all type variables etc + // that we create during the probe process are removed later + self.probe(|_| { + let mut probe_cx = ProbeContext::new(self, + span, + mode, + item_name, + steps, + opt_simplified_steps); + probe_cx.assemble_inherent_candidates(); + probe_cx.assemble_extension_candidates_for_traits_in_scope(scope_expr_id)?; + probe_cx.pick() + }) } - Some(steps) -} + fn create_steps(&self, + span: Span, + self_ty: Ty<'tcx>) + -> Option>> { + let mut steps = Vec::new(); + + let (final_ty, dereferences, _) = self.autoderef(span, + self_ty, + || None, + UnresolvedTypeAction::Error, + NoPreference, + |t, d| { + steps.push(CandidateStep { + self_ty: t, + autoderefs: d, + unsize: false + }); + None::<()> // keep iterating until we can't anymore + }); + + match final_ty.sty { + ty::TyArray(elem_ty, _) => { + steps.push(CandidateStep { + self_ty: self.tcx.mk_slice(elem_ty), + autoderefs: dereferences, + unsize: true + }); + } + ty::TyError => return None, + _ => (), + } + + Some(steps) + } } impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index ed60f9b6e7c..540af8b04bf 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -40,353 +40,353 @@ use super::{MethodError, NoMatchData, CandidateSource}; use super::probe::Mode; impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { -fn is_fn_ty(&self, ty: &Ty<'tcx>, span: Span) -> bool { - let tcx = self.tcx; - match ty.sty { - // Not all of these (e.g. unsafe fns) implement FnOnce - // so we look for these beforehand - ty::TyClosure(..) | ty::TyFnDef(..) | ty::TyFnPtr(_) => true, - // If it's not a simple function, look for things which implement FnOnce - _ => { - if let Ok(fn_once_trait_did) = - tcx.lang_items.require(FnOnceTraitLangItem) { - let (_, _, opt_is_fn) = self.autoderef(span, - ty, - || None, - UnresolvedTypeAction::Ignore, - LvaluePreference::NoPreference, - |ty, _| { - self.probe(|_| { - let fn_once_substs = - Substs::new_trait(vec![self.next_ty_var()], vec![], ty); - let trait_ref = - ty::TraitRef::new(fn_once_trait_did, - tcx.mk_substs(fn_once_substs)); - let poly_trait_ref = trait_ref.to_poly_trait_ref(); - let obligation = Obligation::misc(span, - self.body_id, - poly_trait_ref - .to_predicate()); - let mut selcx = SelectionContext::new(self); + fn is_fn_ty(&self, ty: &Ty<'tcx>, span: Span) -> bool { + let tcx = self.tcx; + match ty.sty { + // Not all of these (e.g. unsafe fns) implement FnOnce + // so we look for these beforehand + ty::TyClosure(..) | ty::TyFnDef(..) | ty::TyFnPtr(_) => true, + // If it's not a simple function, look for things which implement FnOnce + _ => { + if let Ok(fn_once_trait_did) = + tcx.lang_items.require(FnOnceTraitLangItem) { + let (_, _, opt_is_fn) = self.autoderef(span, + ty, + || None, + UnresolvedTypeAction::Ignore, + LvaluePreference::NoPreference, + |ty, _| { + self.probe(|_| { + let fn_once_substs = + Substs::new_trait(vec![self.next_ty_var()], vec![], ty); + let trait_ref = + ty::TraitRef::new(fn_once_trait_did, + tcx.mk_substs(fn_once_substs)); + let poly_trait_ref = trait_ref.to_poly_trait_ref(); + let obligation = Obligation::misc(span, + self.body_id, + poly_trait_ref + .to_predicate()); + let mut selcx = SelectionContext::new(self); - if selcx.evaluate_obligation(&obligation) { - Some(()) - } else { - None - } - }) - }); - - opt_is_fn.is_some() - } else { - false - } - } - } -} -pub fn report_method_error(&self, - span: Span, - rcvr_ty: Ty<'tcx>, - item_name: ast::Name, - rcvr_expr: Option<&hir::Expr>, - error: MethodError<'tcx>) -{ - // avoid suggestions when we don't know what's going on. - if rcvr_ty.references_error() { - return - } - - let report_candidates = |err: &mut DiagnosticBuilder, - mut sources: Vec| { - - sources.sort(); - sources.dedup(); - - for (idx, source) in sources.iter().enumerate() { - match *source { - CandidateSource::ImplSource(impl_did) => { - // Provide the best span we can. Use the item, if local to crate, else - // the impl, if local to crate (item may be defaulted), else nothing. - let item = self.impl_item(impl_did, item_name) - .or_else(|| { - self.trait_item( - self.tcx.impl_trait_ref(impl_did).unwrap().def_id, - - item_name - ) - }).unwrap(); - let note_span = self.tcx.map.span_if_local(item.def_id()).or_else(|| { - self.tcx.map.span_if_local(impl_did) + if selcx.evaluate_obligation(&obligation) { + Some(()) + } else { + None + } + }) }); - let impl_ty = self.impl_self_ty(span, impl_did).ty; - - let insertion = match self.tcx.impl_trait_ref(impl_did) { - None => format!(""), - Some(trait_ref) => { - format!(" of the trait `{}`", - self.tcx.item_path_str(trait_ref.def_id)) - } - }; - - let note_str = format!("candidate #{} is defined in an impl{} \ - for the type `{}`", - idx + 1, - insertion, - impl_ty); - if let Some(note_span) = note_span { - // We have a span pointing to the method. Show note with snippet. - err.span_note(note_span, ¬e_str); - } else { - err.note(¬e_str); - } - } - CandidateSource::TraitSource(trait_did) => { - let item = self.trait_item(trait_did, item_name).unwrap(); - let item_span = self.tcx.map.def_id_span(item.def_id(), span); - span_note!(err, item_span, - "candidate #{} is defined in the trait `{}`", - idx + 1, - self.tcx.item_path_str(trait_did)); + opt_is_fn.is_some() + } else { + false } } } - }; - - match error { - MethodError::NoMatch(NoMatchData { static_candidates: static_sources, - unsatisfied_predicates, - out_of_scope_traits, - mode, .. }) => { - let tcx = self.tcx; - - let mut err = self.type_error_struct( - span, - |actual| { - format!("no {} named `{}` found for type `{}` \ - in the current scope", - if mode == Mode::MethodCall { "method" } - else { "associated item" }, - item_name, - actual) - }, - rcvr_ty, - None); - - // If the item has the name of a field, give a help note - if let (&ty::TyStruct(def, substs), Some(expr)) = (&rcvr_ty.sty, rcvr_expr) { - if let Some(field) = def.struct_variant().find_field_named(item_name) { - let expr_string = match tcx.sess.codemap().span_to_snippet(expr.span) { - Ok(expr_string) => expr_string, - _ => "s".into() // Default to a generic placeholder for the - // expression when we can't generate a string - // snippet - }; - - let field_ty = field.ty(tcx, substs); - - if self.is_fn_ty(&field_ty, span) { - err.span_note(span, - &format!("use `({0}.{1})(...)` if you meant to call \ - the function stored in the `{1}` field", - expr_string, item_name)); - } else { - err.span_note(span, &format!("did you mean to write `{0}.{1}`?", - expr_string, item_name)); - } - } - } - - if self.is_fn_ty(&rcvr_ty, span) { - macro_rules! report_function { - ($span:expr, $name:expr) => { - err.note(&format!("{} is a function, perhaps you wish to call it", - $name)); - } - } - - if let Some(expr) = rcvr_expr { - if let Ok (expr_string) = tcx.sess.codemap().span_to_snippet(expr.span) { - report_function!(expr.span, expr_string); - } - else if let Expr_::ExprPath(_, path) = expr.node.clone() { - if let Some(segment) = path.segments.last() { - report_function!(expr.span, segment.identifier.name); - } - } - } - } - - if !static_sources.is_empty() { - err.note( - "found the following associated functions; to be used as \ - methods, functions must have a `self` parameter"); - - report_candidates(&mut err, static_sources); - } - - if !unsatisfied_predicates.is_empty() { - let bound_list = unsatisfied_predicates.iter() - .map(|p| format!("`{} : {}`", - p.self_ty(), - p)) - .collect::>() - .join(", "); - err.note( - &format!("the method `{}` exists but the \ - following trait bounds were not satisfied: {}", - item_name, - bound_list)); - } - - self.suggest_traits_to_import(&mut err, span, rcvr_ty, item_name, - rcvr_expr, out_of_scope_traits); - err.emit(); - } - - MethodError::Ambiguity(sources) => { - let mut err = struct_span_err!(self.sess(), span, E0034, - "multiple applicable items in scope"); - - report_candidates(&mut err, sources); - err.emit(); - } - - MethodError::ClosureAmbiguity(trait_def_id) => { - let msg = format!("the `{}` method from the `{}` trait cannot be explicitly \ - invoked on this closure as we have not yet inferred what \ - kind of closure it is", - item_name, - self.tcx.item_path_str(trait_def_id)); - let msg = if let Some(callee) = rcvr_expr { - format!("{}; use overloaded call notation instead (e.g., `{}()`)", - msg, pprust::expr_to_string(callee)) - } else { - msg - }; - self.sess().span_err(span, &msg); - } - - MethodError::PrivateMatch(def) => { - let msg = format!("{} `{}` is private", def.kind_name(), item_name); - self.tcx.sess.span_err(span, &msg); - } } -} + pub fn report_method_error(&self, + span: Span, + rcvr_ty: Ty<'tcx>, + item_name: ast::Name, + rcvr_expr: Option<&hir::Expr>, + error: MethodError<'tcx>) + { + // avoid suggestions when we don't know what's going on. + if rcvr_ty.references_error() { + return + } -fn suggest_traits_to_import(&self, - err: &mut DiagnosticBuilder, + let report_candidates = |err: &mut DiagnosticBuilder, + mut sources: Vec| { + + sources.sort(); + sources.dedup(); + + for (idx, source) in sources.iter().enumerate() { + match *source { + CandidateSource::ImplSource(impl_did) => { + // Provide the best span we can. Use the item, if local to crate, else + // the impl, if local to crate (item may be defaulted), else nothing. + let item = self.impl_item(impl_did, item_name) + .or_else(|| { + self.trait_item( + self.tcx.impl_trait_ref(impl_did).unwrap().def_id, + + item_name + ) + }).unwrap(); + let note_span = self.tcx.map.span_if_local(item.def_id()).or_else(|| { + self.tcx.map.span_if_local(impl_did) + }); + + let impl_ty = self.impl_self_ty(span, impl_did).ty; + + let insertion = match self.tcx.impl_trait_ref(impl_did) { + None => format!(""), + Some(trait_ref) => { + format!(" of the trait `{}`", + self.tcx.item_path_str(trait_ref.def_id)) + } + }; + + let note_str = format!("candidate #{} is defined in an impl{} \ + for the type `{}`", + idx + 1, + insertion, + impl_ty); + if let Some(note_span) = note_span { + // We have a span pointing to the method. Show note with snippet. + err.span_note(note_span, ¬e_str); + } else { + err.note(¬e_str); + } + } + CandidateSource::TraitSource(trait_did) => { + let item = self.trait_item(trait_did, item_name).unwrap(); + let item_span = self.tcx.map.def_id_span(item.def_id(), span); + span_note!(err, item_span, + "candidate #{} is defined in the trait `{}`", + idx + 1, + self.tcx.item_path_str(trait_did)); + } + } + } + }; + + match error { + MethodError::NoMatch(NoMatchData { static_candidates: static_sources, + unsatisfied_predicates, + out_of_scope_traits, + mode, .. }) => { + let tcx = self.tcx; + + let mut err = self.type_error_struct( + span, + |actual| { + format!("no {} named `{}` found for type `{}` \ + in the current scope", + if mode == Mode::MethodCall { "method" } + else { "associated item" }, + item_name, + actual) + }, + rcvr_ty, + None); + + // If the item has the name of a field, give a help note + if let (&ty::TyStruct(def, substs), Some(expr)) = (&rcvr_ty.sty, rcvr_expr) { + if let Some(field) = def.struct_variant().find_field_named(item_name) { + let expr_string = match tcx.sess.codemap().span_to_snippet(expr.span) { + Ok(expr_string) => expr_string, + _ => "s".into() // Default to a generic placeholder for the + // expression when we can't generate a string + // snippet + }; + + let field_ty = field.ty(tcx, substs); + + if self.is_fn_ty(&field_ty, span) { + err.span_note(span, + &format!("use `({0}.{1})(...)` if you meant to call \ + the function stored in the `{1}` field", + expr_string, item_name)); + } else { + err.span_note(span, &format!("did you mean to write `{0}.{1}`?", + expr_string, item_name)); + } + } + } + + if self.is_fn_ty(&rcvr_ty, span) { + macro_rules! report_function { + ($span:expr, $name:expr) => { + err.note(&format!("{} is a function, perhaps you wish to call it", + $name)); + } + } + + if let Some(expr) = rcvr_expr { + if let Ok (expr_string) = tcx.sess.codemap().span_to_snippet(expr.span) { + report_function!(expr.span, expr_string); + } + else if let Expr_::ExprPath(_, path) = expr.node.clone() { + if let Some(segment) = path.segments.last() { + report_function!(expr.span, segment.identifier.name); + } + } + } + } + + if !static_sources.is_empty() { + err.note( + "found the following associated functions; to be used as \ + methods, functions must have a `self` parameter"); + + report_candidates(&mut err, static_sources); + } + + if !unsatisfied_predicates.is_empty() { + let bound_list = unsatisfied_predicates.iter() + .map(|p| format!("`{} : {}`", + p.self_ty(), + p)) + .collect::>() + .join(", "); + err.note( + &format!("the method `{}` exists but the \ + following trait bounds were not satisfied: {}", + item_name, + bound_list)); + } + + self.suggest_traits_to_import(&mut err, span, rcvr_ty, item_name, + rcvr_expr, out_of_scope_traits); + err.emit(); + } + + MethodError::Ambiguity(sources) => { + let mut err = struct_span_err!(self.sess(), span, E0034, + "multiple applicable items in scope"); + + report_candidates(&mut err, sources); + err.emit(); + } + + MethodError::ClosureAmbiguity(trait_def_id) => { + let msg = format!("the `{}` method from the `{}` trait cannot be explicitly \ + invoked on this closure as we have not yet inferred what \ + kind of closure it is", + item_name, + self.tcx.item_path_str(trait_def_id)); + let msg = if let Some(callee) = rcvr_expr { + format!("{}; use overloaded call notation instead (e.g., `{}()`)", + msg, pprust::expr_to_string(callee)) + } else { + msg + }; + self.sess().span_err(span, &msg); + } + + MethodError::PrivateMatch(def) => { + let msg = format!("{} `{}` is private", def.kind_name(), item_name); + self.tcx.sess.span_err(span, &msg); + } + } + } + + fn suggest_traits_to_import(&self, + err: &mut DiagnosticBuilder, + span: Span, + rcvr_ty: Ty<'tcx>, + item_name: ast::Name, + rcvr_expr: Option<&hir::Expr>, + valid_out_of_scope_traits: Vec) + { + if !valid_out_of_scope_traits.is_empty() { + let mut candidates = valid_out_of_scope_traits; + candidates.sort(); + candidates.dedup(); + let msg = format!( + "items from traits can only be used if the trait is in scope; \ + the following {traits_are} implemented but not in scope, \ + perhaps add a `use` for {one_of_them}:", + traits_are = if candidates.len() == 1 {"trait is"} else {"traits are"}, + one_of_them = if candidates.len() == 1 {"it"} else {"one of them"}); + + err.help(&msg[..]); + + for (i, trait_did) in candidates.iter().enumerate() { + err.help(&format!("candidate #{}: `use {}`", + i + 1, + self.tcx.item_path_str(*trait_did))); + } + return + } + + let type_is_local = self.type_derefs_to_local(span, rcvr_ty, rcvr_expr); + + // there's no implemented traits, so lets suggest some traits to + // implement, by finding ones that have the item name, and are + // legal to implement. + let mut candidates = all_traits(self.ccx) + .filter(|info| { + // we approximate the coherence rules to only suggest + // traits that are legal to implement by requiring that + // either the type or trait is local. Multidispatch means + // this isn't perfect (that is, there are cases when + // implementing a trait would be legal but is rejected + // here). + (type_is_local || info.def_id.is_local()) + && self.trait_item(info.def_id, item_name).is_some() + }) + .collect::>(); + + if !candidates.is_empty() { + // sort from most relevant to least relevant + candidates.sort_by(|a, b| a.cmp(b).reverse()); + candidates.dedup(); + + // FIXME #21673 this help message could be tuned to the case + // of a type parameter: suggest adding a trait bound rather + // than implementing. + let msg = format!( + "items from traits can only be used if the trait is implemented and in scope; \ + the following {traits_define} an item `{name}`, \ + perhaps you need to implement {one_of_them}:", + traits_define = if candidates.len() == 1 {"trait defines"} else {"traits define"}, + one_of_them = if candidates.len() == 1 {"it"} else {"one of them"}, + name = item_name); + + err.help(&msg[..]); + + for (i, trait_info) in candidates.iter().enumerate() { + err.help(&format!("candidate #{}: `{}`", + i + 1, + self.tcx.item_path_str(trait_info.def_id))); + } + } + } + + /// Checks whether there is a local type somewhere in the chain of + /// autoderefs of `rcvr_ty`. + fn type_derefs_to_local(&self, span: Span, rcvr_ty: Ty<'tcx>, - item_name: ast::Name, - rcvr_expr: Option<&hir::Expr>, - valid_out_of_scope_traits: Vec) -{ - if !valid_out_of_scope_traits.is_empty() { - let mut candidates = valid_out_of_scope_traits; - candidates.sort(); - candidates.dedup(); - let msg = format!( - "items from traits can only be used if the trait is in scope; \ - the following {traits_are} implemented but not in scope, \ - perhaps add a `use` for {one_of_them}:", - traits_are = if candidates.len() == 1 {"trait is"} else {"traits are"}, - one_of_them = if candidates.len() == 1 {"it"} else {"one of them"}); + rcvr_expr: Option<&hir::Expr>) -> bool { + fn is_local(ty: Ty) -> bool { + match ty.sty { + ty::TyEnum(def, _) | ty::TyStruct(def, _) => def.did.is_local(), - err.help(&msg[..]); + ty::TyTrait(ref tr) => tr.principal_def_id().is_local(), - for (i, trait_did) in candidates.iter().enumerate() { - err.help(&format!("candidate #{}: `use {}`", - i + 1, - self.tcx.item_path_str(*trait_did))); + ty::TyParam(_) => true, + + // everything else (primitive types etc.) is effectively + // non-local (there are "edge" cases, e.g. (LocalType,), but + // the noise from these sort of types is usually just really + // annoying, rather than any sort of help). + _ => false + } } - return - } - let type_is_local = self.type_derefs_to_local(span, rcvr_ty, rcvr_expr); - - // there's no implemented traits, so lets suggest some traits to - // implement, by finding ones that have the item name, and are - // legal to implement. - let mut candidates = all_traits(self.ccx) - .filter(|info| { - // we approximate the coherence rules to only suggest - // traits that are legal to implement by requiring that - // either the type or trait is local. Multidispatch means - // this isn't perfect (that is, there are cases when - // implementing a trait would be legal but is rejected - // here). - (type_is_local || info.def_id.is_local()) - && self.trait_item(info.def_id, item_name).is_some() - }) - .collect::>(); - - if !candidates.is_empty() { - // sort from most relevant to least relevant - candidates.sort_by(|a, b| a.cmp(b).reverse()); - candidates.dedup(); - - // FIXME #21673 this help message could be tuned to the case - // of a type parameter: suggest adding a trait bound rather - // than implementing. - let msg = format!( - "items from traits can only be used if the trait is implemented and in scope; \ - the following {traits_define} an item `{name}`, \ - perhaps you need to implement {one_of_them}:", - traits_define = if candidates.len() == 1 {"trait defines"} else {"traits define"}, - one_of_them = if candidates.len() == 1 {"it"} else {"one of them"}, - name = item_name); - - err.help(&msg[..]); - - for (i, trait_info) in candidates.iter().enumerate() { - err.help(&format!("candidate #{}: `{}`", - i + 1, - self.tcx.item_path_str(trait_info.def_id))); + // This occurs for UFCS desugaring of `T::method`, where there is no + // receiver expression for the method call, and thus no autoderef. + if rcvr_expr.is_none() { + return is_local(self.resolve_type_vars_with_obligations(rcvr_ty)); } + + self.autoderef(span, rcvr_ty, || None, + check::UnresolvedTypeAction::Ignore, ty::NoPreference, + |ty, _| { + if is_local(ty) { + Some(()) + } else { + None + } + }).2.is_some() } } -/// Checks whether there is a local type somewhere in the chain of -/// autoderefs of `rcvr_ty`. -fn type_derefs_to_local(&self, - span: Span, - rcvr_ty: Ty<'tcx>, - rcvr_expr: Option<&hir::Expr>) -> bool { - fn is_local(ty: Ty) -> bool { - match ty.sty { - ty::TyEnum(def, _) | ty::TyStruct(def, _) => def.did.is_local(), - - ty::TyTrait(ref tr) => tr.principal_def_id().is_local(), - - ty::TyParam(_) => true, - - // everything else (primitive types etc.) is effectively - // non-local (there are "edge" cases, e.g. (LocalType,), but - // the noise from these sort of types is usually just really - // annoying, rather than any sort of help). - _ => false - } - } - - // This occurs for UFCS desugaring of `T::method`, where there is no - // receiver expression for the method call, and thus no autoderef. - if rcvr_expr.is_none() { - return is_local(self.resolve_type_vars_with_obligations(rcvr_ty)); - } - - self.autoderef(span, rcvr_ty, || None, - check::UnresolvedTypeAction::Ignore, ty::NoPreference, - |ty, _| { - if is_local(ty) { - Some(()) - } else { - None - } - }).2.is_some() -} -} - pub type AllTraitsVec = Vec; #[derive(Copy, Clone)] diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index ad0ccdcf389..f428023da9b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2015,7 +2015,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(_default) = default_map.get(ty) { let resolved = self.resolve_type_vars_if_possible(ty); - debug!("select_all_obligations_and_apply_defaults: ty: {:?} with default: {:?}", + debug!("select_all_obligations_and_apply_defaults: \ + ty: {:?} with default: {:?}", ty, _default); match resolved.sty { @@ -2209,676 +2210,679 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } -/// Executes an autoderef loop for the type `t`. At each step, invokes `should_stop` to decide -/// whether to terminate the loop. Returns the final type and number of derefs that it performed. -/// -/// Note: this method does not modify the adjustments table. The caller is responsible for -/// inserting an AutoAdjustment record into the `self` using one of the suitable methods. -pub fn autoderef<'b, E, I, T, F>(&self, - sp: Span, - base_ty: Ty<'tcx>, - maybe_exprs: E, - unresolved_type_action: UnresolvedTypeAction, - mut lvalue_pref: LvaluePreference, - mut should_stop: F) - -> (Ty<'tcx>, usize, Option) - // FIXME(eddyb) use copyable iterators when that becomes ergonomic. - where E: Fn() -> I, - I: IntoIterator, - F: FnMut(Ty<'tcx>, usize) -> Option, -{ - debug!("autoderef(base_ty={:?}, lvalue_pref={:?})", - base_ty, lvalue_pref); + /// Executes an autoderef loop for the type `t`. At each step, invokes `should_stop` + /// to decide whether to terminate the loop. Returns the final type and number of + /// derefs that it performed. + /// + /// Note: this method does not modify the adjustments table. The caller is responsible for + /// inserting an AutoAdjustment record into the `self` using one of the suitable methods. + pub fn autoderef<'b, E, I, T, F>(&self, + sp: Span, + base_ty: Ty<'tcx>, + maybe_exprs: E, + unresolved_type_action: UnresolvedTypeAction, + mut lvalue_pref: LvaluePreference, + mut should_stop: F) + -> (Ty<'tcx>, usize, Option) + // FIXME(eddyb) use copyable iterators when that becomes ergonomic. + where E: Fn() -> I, + I: IntoIterator, + F: FnMut(Ty<'tcx>, usize) -> Option, + { + debug!("autoderef(base_ty={:?}, lvalue_pref={:?})", + base_ty, lvalue_pref); - let mut t = base_ty; - for autoderefs in 0..self.tcx.sess.recursion_limit.get() { - let resolved_t = match unresolved_type_action { - UnresolvedTypeAction::Error => { - self.structurally_resolved_type(sp, t) + let mut t = base_ty; + for autoderefs in 0..self.tcx.sess.recursion_limit.get() { + let resolved_t = match unresolved_type_action { + UnresolvedTypeAction::Error => { + self.structurally_resolved_type(sp, t) + } + UnresolvedTypeAction::Ignore => { + // We can continue even when the type cannot be resolved + // (i.e. it is an inference variable) because `Ty::builtin_deref` + // and `try_overloaded_deref` both simply return `None` + // in such a case without producing spurious errors. + self.resolve_type_vars_if_possible(&t) + } + }; + if resolved_t.references_error() { + return (resolved_t, autoderefs, None); } - UnresolvedTypeAction::Ignore => { - // We can continue even when the type cannot be resolved - // (i.e. it is an inference variable) because `Ty::builtin_deref` - // and `try_overloaded_deref` both simply return `None` - // in such a case without producing spurious errors. - self.resolve_type_vars_if_possible(&t) + + match should_stop(resolved_t, autoderefs) { + Some(x) => return (resolved_t, autoderefs, Some(x)), + None => {} } + + // Otherwise, deref if type is derefable: + + // Super subtle: it might seem as though we should + // pass `opt_expr` to `try_overloaded_deref`, so that + // the (implicit) autoref of using an overloaded deref + // would get added to the adjustment table. However we + // do not do that, because it's kind of a + // "meta-adjustment" -- instead, we just leave it + // unrecorded and know that there "will be" an + // autoref. regionck and other bits of the code base, + // when they encounter an overloaded autoderef, have + // to do some reconstructive surgery. This is a pretty + // complex mess that is begging for a proper MIR. + let mt = if let Some(mt) = resolved_t.builtin_deref(false, lvalue_pref) { + mt + } else if let Some(method) = self.try_overloaded_deref(sp, None, + resolved_t, lvalue_pref) { + for expr in maybe_exprs() { + let method_call = MethodCall::autoderef(expr.id, autoderefs as u32); + self.tables.borrow_mut().method_map.insert(method_call, method); + } + self.make_overloaded_lvalue_return_type(method) + } else { + return (resolved_t, autoderefs, None); + }; + + t = mt.ty; + if mt.mutbl == hir::MutImmutable { + lvalue_pref = NoPreference; + } + } + + // We've reached the recursion limit, error gracefully. + span_err!(self.tcx.sess, sp, E0055, + "reached the recursion limit while auto-dereferencing {:?}", + base_ty); + (self.tcx.types.err, 0, None) + } + + fn try_overloaded_deref(&self, + span: Span, + base_expr: Option<&hir::Expr>, + base_ty: Ty<'tcx>, + lvalue_pref: LvaluePreference) + -> Option> + { + // Try DerefMut first, if preferred. + let method = match (lvalue_pref, self.tcx.lang_items.deref_mut_trait()) { + (PreferMutLvalue, Some(trait_did)) => { + self.lookup_method_in_trait(span, base_expr, + token::intern("deref_mut"), trait_did, + base_ty, None) + } + _ => None }; - if resolved_t.references_error() { - return (resolved_t, autoderefs, None); - } - match should_stop(resolved_t, autoderefs) { - Some(x) => return (resolved_t, autoderefs, Some(x)), - None => {} - } - - // Otherwise, deref if type is derefable: - - // Super subtle: it might seem as though we should - // pass `opt_expr` to `try_overloaded_deref`, so that - // the (implicit) autoref of using an overloaded deref - // would get added to the adjustment table. However we - // do not do that, because it's kind of a - // "meta-adjustment" -- instead, we just leave it - // unrecorded and know that there "will be" an - // autoref. regionck and other bits of the code base, - // when they encounter an overloaded autoderef, have - // to do some reconstructive surgery. This is a pretty - // complex mess that is begging for a proper MIR. - let mt = if let Some(mt) = resolved_t.builtin_deref(false, lvalue_pref) { - mt - } else if let Some(method) = self.try_overloaded_deref(sp, None, - resolved_t, lvalue_pref) { - for expr in maybe_exprs() { - let method_call = MethodCall::autoderef(expr.id, autoderefs as u32); - self.tables.borrow_mut().method_map.insert(method_call, method); + // Otherwise, fall back to Deref. + let method = match (method, self.tcx.lang_items.deref_trait()) { + (None, Some(trait_did)) => { + self.lookup_method_in_trait(span, base_expr, + token::intern("deref"), trait_did, + base_ty, None) } - self.make_overloaded_lvalue_return_type(method) + (method, _) => method + }; + + method + } + + /// For the overloaded lvalue expressions (`*x`, `x[3]`), the trait + /// returns a type of `&T`, but the actual type we assign to the + /// *expression* is `T`. So this function just peels off the return + /// type by one layer to yield `T`. + fn make_overloaded_lvalue_return_type(&self, + method: MethodCallee<'tcx>) + -> ty::TypeAndMut<'tcx> + { + // extract method return type, which will be &T; + // all LB regions should have been instantiated during method lookup + let ret_ty = method.ty.fn_ret(); + let ret_ty = self.tcx.no_late_bound_regions(&ret_ty).unwrap().unwrap(); + + // method returns &T, but the type as visible to user is T, so deref + ret_ty.builtin_deref(true, NoPreference).unwrap() + } + + fn lookup_indexing(&self, + expr: &hir::Expr, + base_expr: &'gcx hir::Expr, + base_ty: Ty<'tcx>, + idx_ty: Ty<'tcx>, + lvalue_pref: LvaluePreference) + -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> + { + // FIXME(#18741) -- this is almost but not quite the same as the + // autoderef that normal method probing does. They could likely be + // consolidated. + + let (ty, autoderefs, final_mt) = self.autoderef(base_expr.span, + base_ty, + || Some(base_expr), + UnresolvedTypeAction::Error, + lvalue_pref, + |adj_ty, idx| { + self.try_index_step(MethodCall::expr(expr.id), expr, base_expr, + adj_ty, idx, false, lvalue_pref, idx_ty) + }); + + if final_mt.is_some() { + return final_mt; + } + + // After we have fully autoderef'd, if the resulting type is [T; n], then + // do a final unsized coercion to yield [T]. + if let ty::TyArray(element_ty, _) = ty.sty { + let adjusted_ty = self.tcx.mk_slice(element_ty); + self.try_index_step(MethodCall::expr(expr.id), expr, base_expr, + adjusted_ty, autoderefs, true, lvalue_pref, idx_ty) } else { - return (resolved_t, autoderefs, None); + None + } + } + + /// To type-check `base_expr[index_expr]`, we progressively autoderef + /// (and otherwise adjust) `base_expr`, looking for a type which either + /// supports builtin indexing or overloaded indexing. + /// This loop implements one step in that search; the autoderef loop + /// is implemented by `lookup_indexing`. + fn try_index_step(&self, + method_call: MethodCall, + expr: &hir::Expr, + base_expr: &'gcx hir::Expr, + adjusted_ty: Ty<'tcx>, + autoderefs: usize, + unsize: bool, + lvalue_pref: LvaluePreference, + index_ty: Ty<'tcx>) + -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> + { + let tcx = self.tcx; + debug!("try_index_step(expr={:?}, base_expr.id={:?}, adjusted_ty={:?}, \ + autoderefs={}, unsize={}, index_ty={:?})", + expr, + base_expr, + adjusted_ty, + autoderefs, + unsize, + index_ty); + + let input_ty = self.next_ty_var(); + + // First, try built-in indexing. + match (adjusted_ty.builtin_index(), &index_ty.sty) { + (Some(ty), &ty::TyUint(ast::UintTy::Us)) | (Some(ty), &ty::TyInfer(ty::IntVar(_))) => { + debug!("try_index_step: success, using built-in indexing"); + // If we had `[T; N]`, we should've caught it before unsizing to `[T]`. + assert!(!unsize); + self.write_autoderef_adjustment(base_expr.id, autoderefs); + return Some((tcx.types.usize, ty)); + } + _ => {} + } + + // Try `IndexMut` first, if preferred. + let method = match (lvalue_pref, tcx.lang_items.index_mut_trait()) { + (PreferMutLvalue, Some(trait_did)) => { + self.lookup_method_in_trait_adjusted(expr.span, + Some(&base_expr), + token::intern("index_mut"), + trait_did, + autoderefs, + unsize, + adjusted_ty, + Some(vec![input_ty])) + } + _ => None, }; - t = mt.ty; - if mt.mutbl == hir::MutImmutable { - lvalue_pref = NoPreference; - } - } - - // We've reached the recursion limit, error gracefully. - span_err!(self.tcx.sess, sp, E0055, - "reached the recursion limit while auto-dereferencing {:?}", - base_ty); - (self.tcx.types.err, 0, None) -} - -fn try_overloaded_deref(&self, - span: Span, - base_expr: Option<&hir::Expr>, - base_ty: Ty<'tcx>, - lvalue_pref: LvaluePreference) - -> Option> -{ - // Try DerefMut first, if preferred. - let method = match (lvalue_pref, self.tcx.lang_items.deref_mut_trait()) { - (PreferMutLvalue, Some(trait_did)) => { - self.lookup_method_in_trait(span, base_expr, - token::intern("deref_mut"), trait_did, - base_ty, None) - } - _ => None - }; - - // Otherwise, fall back to Deref. - let method = match (method, self.tcx.lang_items.deref_trait()) { - (None, Some(trait_did)) => { - self.lookup_method_in_trait(span, base_expr, - token::intern("deref"), trait_did, - base_ty, None) - } - (method, _) => method - }; - - method -} - -/// For the overloaded lvalue expressions (`*x`, `x[3]`), the trait returns a type of `&T`, but the -/// actual type we assign to the *expression* is `T`. So this function just peels off the return -/// type by one layer to yield `T`. -fn make_overloaded_lvalue_return_type(&self, - method: MethodCallee<'tcx>) - -> ty::TypeAndMut<'tcx> -{ - // extract method return type, which will be &T; - // all LB regions should have been instantiated during method lookup - let ret_ty = method.ty.fn_ret(); - let ret_ty = self.tcx.no_late_bound_regions(&ret_ty).unwrap().unwrap(); - - // method returns &T, but the type as visible to user is T, so deref - ret_ty.builtin_deref(true, NoPreference).unwrap() -} - -fn lookup_indexing(&self, - expr: &hir::Expr, - base_expr: &'gcx hir::Expr, - base_ty: Ty<'tcx>, - idx_ty: Ty<'tcx>, - lvalue_pref: LvaluePreference) - -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> -{ - // FIXME(#18741) -- this is almost but not quite the same as the - // autoderef that normal method probing does. They could likely be - // consolidated. - - let (ty, autoderefs, final_mt) = self.autoderef(base_expr.span, - base_ty, - || Some(base_expr), - UnresolvedTypeAction::Error, - lvalue_pref, - |adj_ty, idx| { - self.try_index_step(MethodCall::expr(expr.id), expr, base_expr, - adj_ty, idx, false, lvalue_pref, idx_ty) - }); - - if final_mt.is_some() { - return final_mt; - } - - // After we have fully autoderef'd, if the resulting type is [T; n], then - // do a final unsized coercion to yield [T]. - if let ty::TyArray(element_ty, _) = ty.sty { - let adjusted_ty = self.tcx.mk_slice(element_ty); - self.try_index_step(MethodCall::expr(expr.id), expr, base_expr, - adjusted_ty, autoderefs, true, lvalue_pref, idx_ty) - } else { - None - } -} - -/// To type-check `base_expr[index_expr]`, we progressively autoderef (and otherwise adjust) -/// `base_expr`, looking for a type which either supports builtin indexing or overloaded indexing. -/// This loop implements one step in that search; the autoderef loop is implemented by -/// `lookup_indexing`. -fn try_index_step(&self, - method_call: MethodCall, - expr: &hir::Expr, - base_expr: &'gcx hir::Expr, - adjusted_ty: Ty<'tcx>, - autoderefs: usize, - unsize: bool, - lvalue_pref: LvaluePreference, - index_ty: Ty<'tcx>) - -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> -{ - let tcx = self.tcx; - debug!("try_index_step(expr={:?}, base_expr.id={:?}, adjusted_ty={:?}, \ - autoderefs={}, unsize={}, index_ty={:?})", - expr, - base_expr, - adjusted_ty, - autoderefs, - unsize, - index_ty); - - let input_ty = self.next_ty_var(); - - // First, try built-in indexing. - match (adjusted_ty.builtin_index(), &index_ty.sty) { - (Some(ty), &ty::TyUint(ast::UintTy::Us)) | (Some(ty), &ty::TyInfer(ty::IntVar(_))) => { - debug!("try_index_step: success, using built-in indexing"); - // If we had `[T; N]`, we should've caught it before unsizing to `[T]`. - assert!(!unsize); - self.write_autoderef_adjustment(base_expr.id, autoderefs); - return Some((tcx.types.usize, ty)); - } - _ => {} - } - - // Try `IndexMut` first, if preferred. - let method = match (lvalue_pref, tcx.lang_items.index_mut_trait()) { - (PreferMutLvalue, Some(trait_did)) => { - self.lookup_method_in_trait_adjusted(expr.span, - Some(&base_expr), - token::intern("index_mut"), - trait_did, - autoderefs, - unsize, - adjusted_ty, - Some(vec![input_ty])) - } - _ => None, - }; - - // Otherwise, fall back to `Index`. - let method = match (method, tcx.lang_items.index_trait()) { - (None, Some(trait_did)) => { - self.lookup_method_in_trait_adjusted(expr.span, - Some(&base_expr), - token::intern("index"), - trait_did, - autoderefs, - unsize, - adjusted_ty, - Some(vec![input_ty])) - } - (method, _) => method, - }; - - // If some lookup succeeds, write callee into table and extract index/element - // type from the method signature. - // If some lookup succeeded, install method in table - method.map(|method| { - debug!("try_index_step: success, using overloaded indexing"); - self.tables.borrow_mut().method_map.insert(method_call, method); - (input_ty, self.make_overloaded_lvalue_return_type(method).ty) - }) -} - -fn check_method_argument_types(&self, - sp: Span, - method_fn_ty: Ty<'tcx>, - callee_expr: &'gcx hir::Expr, - args_no_rcvr: &'gcx [P], - tuple_arguments: TupleArgumentsFlag, - expected: Expectation<'tcx>) - -> ty::FnOutput<'tcx> { - if method_fn_ty.references_error() { - let err_inputs = self.err_args(args_no_rcvr.len()); - - let err_inputs = match tuple_arguments { - DontTupleArguments => err_inputs, - TupleArguments => vec![self.tcx.mk_tup(err_inputs)], + // Otherwise, fall back to `Index`. + let method = match (method, tcx.lang_items.index_trait()) { + (None, Some(trait_did)) => { + self.lookup_method_in_trait_adjusted(expr.span, + Some(&base_expr), + token::intern("index"), + trait_did, + autoderefs, + unsize, + adjusted_ty, + Some(vec![input_ty])) + } + (method, _) => method, }; - self.check_argument_types(sp, &err_inputs[..], &[], args_no_rcvr, - false, tuple_arguments); - ty::FnConverging(self.tcx.types.err) - } else { - match method_fn_ty.sty { - ty::TyFnDef(_, _, ref fty) => { - // HACK(eddyb) ignore self in the definition (see above). - let expected_arg_tys = self.expected_types_for_fn_args(sp, expected, - fty.sig.0.output, - &fty.sig.0.inputs[1..]); - self.check_argument_types(sp, &fty.sig.0.inputs[1..], &expected_arg_tys[..], - args_no_rcvr, fty.sig.0.variadic, tuple_arguments); - fty.sig.0.output - } - _ => { - span_bug!(callee_expr.span, "method without bare fn type"); - } - } - } -} - -/// Generic function that factors out common logic from function calls, method calls and overloaded -/// operators. -fn check_argument_types(&self, - sp: Span, - fn_inputs: &[Ty<'tcx>], - expected_arg_tys: &[Ty<'tcx>], - args: &'gcx [P], - variadic: bool, - tuple_arguments: TupleArgumentsFlag) { - let tcx = self.tcx; - - // Grab the argument types, supplying fresh type variables - // if the wrong number of arguments were supplied - let supplied_arg_count = if tuple_arguments == DontTupleArguments { - args.len() - } else { - 1 - }; - - // All the input types from the fn signature must outlive the call - // so as to validate implied bounds. - for &fn_input_ty in fn_inputs { - self.register_wf_obligation(fn_input_ty, sp, traits::MiscObligation); + // If some lookup succeeds, write callee into table and extract index/element + // type from the method signature. + // If some lookup succeeded, install method in table + method.map(|method| { + debug!("try_index_step: success, using overloaded indexing"); + self.tables.borrow_mut().method_map.insert(method_call, method); + (input_ty, self.make_overloaded_lvalue_return_type(method).ty) + }) } - let mut expected_arg_tys = expected_arg_tys; - let expected_arg_count = fn_inputs.len(); - let formal_tys = if tuple_arguments == TupleArguments { - let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]); - match tuple_type.sty { - ty::TyTuple(arg_types) => { - if arg_types.len() != args.len() { - span_err!(tcx.sess, sp, E0057, - "this function takes {} parameter{} but {} parameter{} supplied", - arg_types.len(), - if arg_types.len() == 1 {""} else {"s"}, - args.len(), - if args.len() == 1 {" was"} else {"s were"}); - expected_arg_tys = &[]; - self.err_args(args.len()) - } else { - expected_arg_tys = match expected_arg_tys.get(0) { - Some(&ty) => match ty.sty { - ty::TyTuple(ref tys) => &tys, - _ => &[] - }, - None => &[] - }; - arg_types.to_vec() + fn check_method_argument_types(&self, + sp: Span, + method_fn_ty: Ty<'tcx>, + callee_expr: &'gcx hir::Expr, + args_no_rcvr: &'gcx [P], + tuple_arguments: TupleArgumentsFlag, + expected: Expectation<'tcx>) + -> ty::FnOutput<'tcx> { + if method_fn_ty.references_error() { + let err_inputs = self.err_args(args_no_rcvr.len()); + + let err_inputs = match tuple_arguments { + DontTupleArguments => err_inputs, + TupleArguments => vec![self.tcx.mk_tup(err_inputs)], + }; + + self.check_argument_types(sp, &err_inputs[..], &[], args_no_rcvr, + false, tuple_arguments); + ty::FnConverging(self.tcx.types.err) + } else { + match method_fn_ty.sty { + ty::TyFnDef(_, _, ref fty) => { + // HACK(eddyb) ignore self in the definition (see above). + let expected_arg_tys = self.expected_types_for_fn_args(sp, expected, + fty.sig.0.output, + &fty.sig.0.inputs[1..]); + self.check_argument_types(sp, &fty.sig.0.inputs[1..], &expected_arg_tys[..], + args_no_rcvr, fty.sig.0.variadic, tuple_arguments); + fty.sig.0.output + } + _ => { + span_bug!(callee_expr.span, "method without bare fn type"); } } - _ => { - span_err!(tcx.sess, sp, E0059, - "cannot use call notation; the first type parameter \ - for the function trait is neither a tuple nor unit"); - expected_arg_tys = &[]; - self.err_args(args.len()) - } } - } else if expected_arg_count == supplied_arg_count { - fn_inputs.to_vec() - } else if variadic { - if supplied_arg_count >= expected_arg_count { - fn_inputs.to_vec() + } + + /// Generic function that factors out common logic from function calls, + /// method calls and overloaded operators. + fn check_argument_types(&self, + sp: Span, + fn_inputs: &[Ty<'tcx>], + expected_arg_tys: &[Ty<'tcx>], + args: &'gcx [P], + variadic: bool, + tuple_arguments: TupleArgumentsFlag) { + let tcx = self.tcx; + + // Grab the argument types, supplying fresh type variables + // if the wrong number of arguments were supplied + let supplied_arg_count = if tuple_arguments == DontTupleArguments { + args.len() } else { - span_err!(tcx.sess, sp, E0060, - "this function takes at least {} parameter{} \ - but {} parameter{} supplied", + 1 + }; + + // All the input types from the fn signature must outlive the call + // so as to validate implied bounds. + for &fn_input_ty in fn_inputs { + self.register_wf_obligation(fn_input_ty, sp, traits::MiscObligation); + } + + let mut expected_arg_tys = expected_arg_tys; + let expected_arg_count = fn_inputs.len(); + let formal_tys = if tuple_arguments == TupleArguments { + let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]); + match tuple_type.sty { + ty::TyTuple(arg_types) => { + if arg_types.len() != args.len() { + span_err!(tcx.sess, sp, E0057, + "this function takes {} parameter{} but {} parameter{} supplied", + arg_types.len(), + if arg_types.len() == 1 {""} else {"s"}, + args.len(), + if args.len() == 1 {" was"} else {"s were"}); + expected_arg_tys = &[]; + self.err_args(args.len()) + } else { + expected_arg_tys = match expected_arg_tys.get(0) { + Some(&ty) => match ty.sty { + ty::TyTuple(ref tys) => &tys, + _ => &[] + }, + None => &[] + }; + arg_types.to_vec() + } + } + _ => { + span_err!(tcx.sess, sp, E0059, + "cannot use call notation; the first type parameter \ + for the function trait is neither a tuple nor unit"); + expected_arg_tys = &[]; + self.err_args(args.len()) + } + } + } else if expected_arg_count == supplied_arg_count { + fn_inputs.to_vec() + } else if variadic { + if supplied_arg_count >= expected_arg_count { + fn_inputs.to_vec() + } else { + span_err!(tcx.sess, sp, E0060, + "this function takes at least {} parameter{} \ + but {} parameter{} supplied", + expected_arg_count, + if expected_arg_count == 1 {""} else {"s"}, + supplied_arg_count, + if supplied_arg_count == 1 {" was"} else {"s were"}); + expected_arg_tys = &[]; + self.err_args(supplied_arg_count) + } + } else { + span_err!(tcx.sess, sp, E0061, + "this function takes {} parameter{} but {} parameter{} supplied", expected_arg_count, if expected_arg_count == 1 {""} else {"s"}, supplied_arg_count, if supplied_arg_count == 1 {" was"} else {"s were"}); expected_arg_tys = &[]; self.err_args(supplied_arg_count) - } - } else { - span_err!(tcx.sess, sp, E0061, - "this function takes {} parameter{} but {} parameter{} supplied", - expected_arg_count, - if expected_arg_count == 1 {""} else {"s"}, - supplied_arg_count, - if supplied_arg_count == 1 {" was"} else {"s were"}); - expected_arg_tys = &[]; - self.err_args(supplied_arg_count) - }; - - debug!("check_argument_types: formal_tys={:?}", - formal_tys.iter().map(|t| self.ty_to_string(*t)).collect::>()); - - // Check the arguments. - // We do this in a pretty awful way: first we typecheck any arguments - // that are not anonymous functions, then we typecheck the anonymous - // functions. This is so that we have more information about the types - // of arguments when we typecheck the functions. This isn't really the - // right way to do this. - let xs = [false, true]; - let mut any_diverges = false; // has any of the arguments diverged? - let mut warned = false; // have we already warned about unreachable code? - for check_blocks in &xs { - let check_blocks = *check_blocks; - debug!("check_blocks={}", check_blocks); - - // More awful hacks: before we check argument types, try to do - // an "opportunistic" vtable resolution of any trait bounds on - // the call. This helps coercions. - if check_blocks { - self.select_obligations_where_possible(); - } - - // For variadic functions, we don't have a declared type for all of - // the arguments hence we only do our usual type checking with - // the arguments who's types we do know. - let t = if variadic { - expected_arg_count - } else if tuple_arguments == TupleArguments { - args.len() - } else { - supplied_arg_count }; - for (i, arg) in args.iter().take(t).enumerate() { + + debug!("check_argument_types: formal_tys={:?}", + formal_tys.iter().map(|t| self.ty_to_string(*t)).collect::>()); + + // Check the arguments. + // We do this in a pretty awful way: first we typecheck any arguments + // that are not anonymous functions, then we typecheck the anonymous + // functions. This is so that we have more information about the types + // of arguments when we typecheck the functions. This isn't really the + // right way to do this. + let xs = [false, true]; + let mut any_diverges = false; // has any of the arguments diverged? + let mut warned = false; // have we already warned about unreachable code? + for check_blocks in &xs { + let check_blocks = *check_blocks; + debug!("check_blocks={}", check_blocks); + + // More awful hacks: before we check argument types, try to do + // an "opportunistic" vtable resolution of any trait bounds on + // the call. This helps coercions. + if check_blocks { + self.select_obligations_where_possible(); + } + + // For variadic functions, we don't have a declared type for all of + // the arguments hence we only do our usual type checking with + // the arguments who's types we do know. + let t = if variadic { + expected_arg_count + } else if tuple_arguments == TupleArguments { + args.len() + } else { + supplied_arg_count + }; + for (i, arg) in args.iter().take(t).enumerate() { + if any_diverges && !warned { + self.tcx + .sess + .add_lint(lint::builtin::UNREACHABLE_CODE, + arg.id, + arg.span, + "unreachable expression".to_string()); + warned = true; + } + let is_block = match arg.node { + hir::ExprClosure(..) => true, + _ => false + }; + + if is_block == check_blocks { + debug!("checking the argument"); + let formal_ty = formal_tys[i]; + + // The special-cased logic below has three functions: + // 1. Provide as good of an expected type as possible. + let expected = expected_arg_tys.get(i).map(|&ty| { + Expectation::rvalue_hint(self, ty) + }); + + self.check_expr_with_expectation(&arg, + expected.unwrap_or(ExpectHasType(formal_ty))); + // 2. Coerce to the most detailed type that could be coerced + // to, which is `expected_ty` if `rvalue_hint` returns an + // `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise. + let coerce_ty = expected.and_then(|e| e.only_has_type(self)); + self.demand_coerce(&arg, coerce_ty.unwrap_or(formal_ty)); + + // 3. Relate the expected type and the formal one, + // if the expected type was used for the coercion. + coerce_ty.map(|ty| self.demand_suptype(arg.span, formal_ty, ty)); + } + + if let Some(&arg_ty) = self.tables.borrow().node_types.get(&arg.id) { + any_diverges = any_diverges || self.type_var_diverges(arg_ty); + } + } if any_diverges && !warned { + let parent = self.tcx.map.get_parent_node(args[0].id); self.tcx .sess .add_lint(lint::builtin::UNREACHABLE_CODE, - arg.id, - arg.span, - "unreachable expression".to_string()); + parent, + sp, + "unreachable call".to_string()); warned = true; } - let is_block = match arg.node { - hir::ExprClosure(..) => true, - _ => false - }; - if is_block == check_blocks { - debug!("checking the argument"); - let formal_ty = formal_tys[i]; + } - // The special-cased logic below has three functions: - // 1. Provide as good of an expected type as possible. - let expected = expected_arg_tys.get(i).map(|&ty| { - Expectation::rvalue_hint(self, ty) + // We also need to make sure we at least write the ty of the other + // arguments which we skipped above. + if variadic { + for arg in args.iter().skip(expected_arg_count) { + self.check_expr(&arg); + + // There are a few types which get autopromoted when passed via varargs + // in C but we just error out instead and require explicit casts. + let arg_ty = self.structurally_resolved_type(arg.span, + self.expr_ty(&arg)); + match arg_ty.sty { + ty::TyFloat(ast::FloatTy::F32) => { + self.type_error_message(arg.span, |t| { + format!("can't pass an `{}` to variadic \ + function, cast to `c_double`", t) + }, arg_ty, None); + } + ty::TyInt(ast::IntTy::I8) | ty::TyInt(ast::IntTy::I16) | ty::TyBool => { + self.type_error_message(arg.span, |t| { + format!("can't pass `{}` to variadic \ + function, cast to `c_int`", + t) + }, arg_ty, None); + } + ty::TyUint(ast::UintTy::U8) | ty::TyUint(ast::UintTy::U16) => { + self.type_error_message(arg.span, |t| { + format!("can't pass `{}` to variadic \ + function, cast to `c_uint`", + t) + }, arg_ty, None); + } + ty::TyFnDef(_, _, f) => { + let ptr_ty = self.tcx.mk_fn_ptr(f); + let ptr_ty = self.resolve_type_vars_if_possible(&ptr_ty); + self.type_error_message(arg.span, + |t| { + format!("can't pass `{}` to variadic \ + function, cast to `{}`", t, ptr_ty) + }, arg_ty, None); + } + _ => {} + } + } + } + } + + fn err_args(&self, len: usize) -> Vec> { + (0..len).map(|_| self.tcx.types.err).collect() + } + + fn write_call(&self, + call_expr: &hir::Expr, + output: ty::FnOutput<'tcx>) { + self.write_ty(call_expr.id, match output { + ty::FnConverging(output_ty) => output_ty, + ty::FnDiverging => self.next_diverging_ty_var() + }); + } + + // AST fragment checking + fn check_lit(&self, + lit: &ast::Lit, + expected: Expectation<'tcx>) + -> Ty<'tcx> + { + let tcx = self.tcx; + + match lit.node { + ast::LitKind::Str(..) => tcx.mk_static_str(), + ast::LitKind::ByteStr(ref v) => { + tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), + tcx.mk_array(tcx.types.u8, v.len())) + } + ast::LitKind::Byte(_) => tcx.types.u8, + ast::LitKind::Char(_) => tcx.types.char, + ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => tcx.mk_mach_int(t), + ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => tcx.mk_mach_uint(t), + ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => { + let opt_ty = expected.to_option(self).and_then(|ty| { + match ty.sty { + ty::TyInt(_) | ty::TyUint(_) => Some(ty), + ty::TyChar => Some(tcx.types.u8), + ty::TyRawPtr(..) => Some(tcx.types.usize), + ty::TyFnDef(..) | ty::TyFnPtr(_) => Some(tcx.types.usize), + _ => None + } }); - - self.check_expr_with_expectation(&arg, - expected.unwrap_or(ExpectHasType(formal_ty))); - // 2. Coerce to the most detailed type that could be coerced - // to, which is `expected_ty` if `rvalue_hint` returns an - // `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise. - let coerce_ty = expected.and_then(|e| e.only_has_type(self)); - self.demand_coerce(&arg, coerce_ty.unwrap_or(formal_ty)); - - // 3. Relate the expected type and the formal one, - // if the expected type was used for the coercion. - coerce_ty.map(|ty| self.demand_suptype(arg.span, formal_ty, ty)); + opt_ty.unwrap_or_else( + || tcx.mk_int_var(self.next_int_var_id())) } - - if let Some(&arg_ty) = self.tables.borrow().node_types.get(&arg.id) { - any_diverges = any_diverges || self.type_var_diverges(arg_ty); + ast::LitKind::Float(_, t) => tcx.mk_mach_float(t), + ast::LitKind::FloatUnsuffixed(_) => { + let opt_ty = expected.to_option(self).and_then(|ty| { + match ty.sty { + ty::TyFloat(_) => Some(ty), + _ => None + } + }); + opt_ty.unwrap_or_else( + || tcx.mk_float_var(self.next_float_var_id())) } + ast::LitKind::Bool(_) => tcx.types.bool } - if any_diverges && !warned { - let parent = self.tcx.map.get_parent_node(args[0].id); - self.tcx - .sess - .add_lint(lint::builtin::UNREACHABLE_CODE, - parent, - sp, - "unreachable call".to_string()); - warned = true; - } - } - // We also need to make sure we at least write the ty of the other - // arguments which we skipped above. - if variadic { - for arg in args.iter().skip(expected_arg_count) { - self.check_expr(&arg); - - // There are a few types which get autopromoted when passed via varargs - // in C but we just error out instead and require explicit casts. - let arg_ty = self.structurally_resolved_type(arg.span, - self.expr_ty(&arg)); - match arg_ty.sty { - ty::TyFloat(ast::FloatTy::F32) => { - self.type_error_message(arg.span, |t| { - format!("can't pass an `{}` to variadic \ - function, cast to `c_double`", t) - }, arg_ty, None); - } - ty::TyInt(ast::IntTy::I8) | ty::TyInt(ast::IntTy::I16) | ty::TyBool => { - self.type_error_message(arg.span, |t| { - format!("can't pass `{}` to variadic \ - function, cast to `c_int`", - t) - }, arg_ty, None); - } - ty::TyUint(ast::UintTy::U8) | ty::TyUint(ast::UintTy::U16) => { - self.type_error_message(arg.span, |t| { - format!("can't pass `{}` to variadic \ - function, cast to `c_uint`", - t) - }, arg_ty, None); - } - ty::TyFnDef(_, _, f) => { - let ptr_ty = self.tcx.mk_fn_ptr(f); - let ptr_ty = self.resolve_type_vars_if_possible(&ptr_ty); - self.type_error_message(arg.span, - |t| { - format!("can't pass `{}` to variadic \ - function, cast to `{}`", t, ptr_ty) - }, arg_ty, None); - } - _ => {} - } - } + fn check_expr_eq_type(&self, + expr: &'gcx hir::Expr, + expected: Ty<'tcx>) { + self.check_expr_with_hint(expr, expected); + self.demand_eqtype(expr.span, expected, self.expr_ty(expr)); } -} -fn err_args(&self, len: usize) -> Vec> { - (0..len).map(|_| self.tcx.types.err).collect() -} - -fn write_call(&self, - call_expr: &hir::Expr, - output: ty::FnOutput<'tcx>) { - self.write_ty(call_expr.id, match output { - ty::FnConverging(output_ty) => output_ty, - ty::FnDiverging => self.next_diverging_ty_var() - }); -} - -// AST fragment checking -fn check_lit(&self, - lit: &ast::Lit, - expected: Expectation<'tcx>) - -> Ty<'tcx> -{ - let tcx = self.tcx; - - match lit.node { - ast::LitKind::Str(..) => tcx.mk_static_str(), - ast::LitKind::ByteStr(ref v) => { - tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), - tcx.mk_array(tcx.types.u8, v.len())) - } - ast::LitKind::Byte(_) => tcx.types.u8, - ast::LitKind::Char(_) => tcx.types.char, - ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => tcx.mk_mach_int(t), - ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => tcx.mk_mach_uint(t), - ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => { - let opt_ty = expected.to_option(self).and_then(|ty| { - match ty.sty { - ty::TyInt(_) | ty::TyUint(_) => Some(ty), - ty::TyChar => Some(tcx.types.u8), - ty::TyRawPtr(..) => Some(tcx.types.usize), - ty::TyFnDef(..) | ty::TyFnPtr(_) => Some(tcx.types.usize), - _ => None - } - }); - opt_ty.unwrap_or_else( - || tcx.mk_int_var(self.next_int_var_id())) - } - ast::LitKind::Float(_, t) => tcx.mk_mach_float(t), - ast::LitKind::FloatUnsuffixed(_) => { - let opt_ty = expected.to_option(self).and_then(|ty| { - match ty.sty { - ty::TyFloat(_) => Some(ty), - _ => None - } - }); - opt_ty.unwrap_or_else( - || tcx.mk_float_var(self.next_float_var_id())) - } - ast::LitKind::Bool(_) => tcx.types.bool - } -} - -fn check_expr_eq_type(&self, - expr: &'gcx hir::Expr, - expected: Ty<'tcx>) { - self.check_expr_with_hint(expr, expected); - self.demand_eqtype(expr.span, expected, self.expr_ty(expr)); -} - -pub fn check_expr_has_type(&self, - expr: &'gcx hir::Expr, - expected: Ty<'tcx>) { - self.check_expr_with_hint(expr, expected); - self.demand_suptype(expr.span, expected, self.expr_ty(expr)); -} - -fn check_expr_coercable_to_type(&self, - expr: &'gcx hir::Expr, - expected: Ty<'tcx>) { - self.check_expr_with_hint(expr, expected); - self.demand_coerce(expr, expected); -} - -fn check_expr_with_hint(&self, expr: &'gcx hir::Expr, - expected: Ty<'tcx>) { - self.check_expr_with_expectation(expr, ExpectHasType(expected)) -} - -fn check_expr_with_expectation(&self, + pub fn check_expr_has_type(&self, expr: &'gcx hir::Expr, - expected: Expectation<'tcx>) { - self.check_expr_with_expectation_and_lvalue_pref(expr, expected, NoPreference) -} + expected: Ty<'tcx>) { + self.check_expr_with_hint(expr, expected); + self.demand_suptype(expr.span, expected, self.expr_ty(expr)); + } -fn check_expr(&self, expr: &'gcx hir::Expr) { - self.check_expr_with_expectation(expr, NoExpectation) -} + fn check_expr_coercable_to_type(&self, + expr: &'gcx hir::Expr, + expected: Ty<'tcx>) { + self.check_expr_with_hint(expr, expected); + self.demand_coerce(expr, expected); + } -fn check_expr_with_lvalue_pref(&self, expr: &'gcx hir::Expr, - lvalue_pref: LvaluePreference) { - self.check_expr_with_expectation_and_lvalue_pref(expr, NoExpectation, lvalue_pref) -} + fn check_expr_with_hint(&self, expr: &'gcx hir::Expr, + expected: Ty<'tcx>) { + self.check_expr_with_expectation(expr, ExpectHasType(expected)) + } -// determine the `self` type, using fresh variables for all variables -// declared on the impl declaration e.g., `impl for Vec<(A,B)>` -// would return ($0, $1) where $0 and $1 are freshly instantiated type -// variables. -pub fn impl_self_ty(&self, - span: Span, // (potential) receiver for this impl - did: DefId) - -> TypeAndSubsts<'tcx> { - let tcx = self.tcx; + fn check_expr_with_expectation(&self, + expr: &'gcx hir::Expr, + expected: Expectation<'tcx>) { + self.check_expr_with_expectation_and_lvalue_pref(expr, expected, NoPreference) + } - let ity = tcx.lookup_item_type(did); - let (tps, rps, raw_ty) = - (ity.generics.types.get_slice(subst::TypeSpace), - ity.generics.regions.get_slice(subst::TypeSpace), - ity.ty); + fn check_expr(&self, expr: &'gcx hir::Expr) { + self.check_expr_with_expectation(expr, NoExpectation) + } - debug!("impl_self_ty: tps={:?} rps={:?} raw_ty={:?}", tps, rps, raw_ty); + fn check_expr_with_lvalue_pref(&self, expr: &'gcx hir::Expr, + lvalue_pref: LvaluePreference) { + self.check_expr_with_expectation_and_lvalue_pref(expr, NoExpectation, lvalue_pref) + } - let rps = self.region_vars_for_defs(span, rps); - let mut substs = subst::Substs::new( - VecPerParamSpace::empty(), - VecPerParamSpace::new(rps, Vec::new(), Vec::new())); - self.type_vars_for_defs(span, ParamSpace::TypeSpace, &mut substs, tps); - let substd_ty = self.instantiate_type_scheme(span, &substs, &raw_ty); + // determine the `self` type, using fresh variables for all variables + // declared on the impl declaration e.g., `impl for Vec<(A,B)>` + // would return ($0, $1) where $0 and $1 are freshly instantiated type + // variables. + pub fn impl_self_ty(&self, + span: Span, // (potential) receiver for this impl + did: DefId) + -> TypeAndSubsts<'tcx> { + let tcx = self.tcx; - TypeAndSubsts { substs: substs, ty: substd_ty } -} + let ity = tcx.lookup_item_type(did); + let (tps, rps, raw_ty) = + (ity.generics.types.get_slice(subst::TypeSpace), + ity.generics.regions.get_slice(subst::TypeSpace), + ity.ty); -/// Unifies the return type with the expected type early, for more coercions -/// and forward type information on the argument expressions. -fn expected_types_for_fn_args(&self, - call_span: Span, - expected_ret: Expectation<'tcx>, - formal_ret: ty::FnOutput<'tcx>, - formal_args: &[Ty<'tcx>]) - -> Vec> { - let expected_args = expected_ret.only_has_type(self).and_then(|ret_ty| { - if let ty::FnConverging(formal_ret_ty) = formal_ret { - self.commit_regions_if_ok(|| { - // Attempt to apply a subtyping relationship between the formal - // return type (likely containing type variables if the function - // is polymorphic) and the expected return type. - // No argument expectations are produced if unification fails. - let origin = TypeOrigin::Misc(call_span); - let ures = self.sub_types(false, origin, formal_ret_ty, ret_ty); - // FIXME(#15760) can't use try! here, FromError doesn't default - // to identity so the resulting type is not constrained. - match ures { - // FIXME(#32730) propagate obligations - Ok(InferOk { obligations, .. }) => assert!(obligations.is_empty()), - Err(e) => return Err(e), - } + debug!("impl_self_ty: tps={:?} rps={:?} raw_ty={:?}", tps, rps, raw_ty); - // Record all the argument types, with the substitutions - // produced from the above subtyping unification. - Ok(formal_args.iter().map(|ty| { - self.resolve_type_vars_if_possible(ty) - }).collect()) - }).ok() - } else { - None - } - }).unwrap_or(vec![]); - debug!("expected_types_for_fn_args(formal={:?} -> {:?}, expected={:?} -> {:?})", - formal_args, formal_ret, - expected_args, expected_ret); - expected_args -} + let rps = self.region_vars_for_defs(span, rps); + let mut substs = subst::Substs::new( + VecPerParamSpace::empty(), + VecPerParamSpace::new(rps, Vec::new(), Vec::new())); + self.type_vars_for_defs(span, ParamSpace::TypeSpace, &mut substs, tps); + let substd_ty = self.instantiate_type_scheme(span, &substs, &raw_ty); + + TypeAndSubsts { substs: substs, ty: substd_ty } + } + + /// Unifies the return type with the expected type early, for more coercions + /// and forward type information on the argument expressions. + fn expected_types_for_fn_args(&self, + call_span: Span, + expected_ret: Expectation<'tcx>, + formal_ret: ty::FnOutput<'tcx>, + formal_args: &[Ty<'tcx>]) + -> Vec> { + let expected_args = expected_ret.only_has_type(self).and_then(|ret_ty| { + if let ty::FnConverging(formal_ret_ty) = formal_ret { + self.commit_regions_if_ok(|| { + // Attempt to apply a subtyping relationship between the formal + // return type (likely containing type variables if the function + // is polymorphic) and the expected return type. + // No argument expectations are produced if unification fails. + let origin = TypeOrigin::Misc(call_span); + let ures = self.sub_types(false, origin, formal_ret_ty, ret_ty); + // FIXME(#15760) can't use try! here, FromError doesn't default + // to identity so the resulting type is not constrained. + match ures { + // FIXME(#32730) propagate obligations + Ok(InferOk { obligations, .. }) => assert!(obligations.is_empty()), + Err(e) => return Err(e), + } + + // Record all the argument types, with the substitutions + // produced from the above subtyping unification. + Ok(formal_args.iter().map(|ty| { + self.resolve_type_vars_if_possible(ty) + }).collect()) + }).ok() + } else { + None + } + }).unwrap_or(vec![]); + debug!("expected_types_for_fn_args(formal={:?} -> {:?}, expected={:?} -> {:?})", + formal_args, formal_ret, + expected_args, expected_ret); + expected_args + } // Checks a method call. fn check_method_call(&self, @@ -3319,1078 +3323,1080 @@ fn expected_types_for_fn_args(&self, } -/// Invariant: -/// If an expression has any sub-expressions that result in a type error, -/// inspecting that expression's type with `ty.references_error()` will return -/// true. Likewise, if an expression is known to diverge, inspecting its -/// type with `ty::type_is_bot` will return true (n.b.: since Rust is -/// strict, _|_ can appear in the type of an expression that does not, -/// itself, diverge: for example, fn() -> _|_.) -/// Note that inspecting a type's structure *directly* may expose the fact -/// that there are actually multiple representations for `TyError`, so avoid -/// that when err needs to be handled differently. -fn check_expr_with_expectation_and_lvalue_pref(&self, - expr: &'gcx hir::Expr, - expected: Expectation<'tcx>, - lvalue_pref: LvaluePreference) { - debug!(">> typechecking: expr={:?} expected={:?}", - expr, expected); - - let tcx = self.tcx; - let id = expr.id; - match expr.node { - hir::ExprBox(ref subexpr) => { - let expected_inner = expected.to_option(self).map_or(NoExpectation, |ty| { - match ty.sty { - ty::TyBox(ty) => Expectation::rvalue_hint(self, ty), - _ => NoExpectation - } - }); - self.check_expr_with_expectation(subexpr, expected_inner); - let referent_ty = self.expr_ty(&subexpr); - self.write_ty(id, tcx.mk_box(referent_ty)); - } - - hir::ExprLit(ref lit) => { - let typ = self.check_lit(&lit, expected); - self.write_ty(id, typ); - } - hir::ExprBinary(op, ref lhs, ref rhs) => { - self.check_binop(expr, op, lhs, rhs); - } - hir::ExprAssignOp(op, ref lhs, ref rhs) => { - self.check_binop_assign(expr, op, lhs, rhs); - } - hir::ExprUnary(unop, ref oprnd) => { - let expected_inner = match unop { - hir::UnNot | hir::UnNeg => { - expected - } - hir::UnDeref => { - NoExpectation - } - }; - let lvalue_pref = match unop { - hir::UnDeref => lvalue_pref, - _ => NoPreference - }; - self.check_expr_with_expectation_and_lvalue_pref(&oprnd, - expected_inner, - lvalue_pref); - let mut oprnd_t = self.expr_ty(&oprnd); - - if !oprnd_t.references_error() { - match unop { - hir::UnDeref => { - oprnd_t = self.structurally_resolved_type(expr.span, oprnd_t); - - if let Some(mt) = oprnd_t.builtin_deref(true, NoPreference) { - oprnd_t = mt.ty; - } else if let Some(method) = self.try_overloaded_deref( - expr.span, Some(&oprnd), oprnd_t, lvalue_pref) { - oprnd_t = self.make_overloaded_lvalue_return_type(method).ty; - self.tables.borrow_mut().method_map.insert(MethodCall::expr(expr.id), - method); - } else { - self.type_error_message(expr.span, |actual| { - format!("type `{}` cannot be \ - dereferenced", actual) - }, oprnd_t, None); - oprnd_t = tcx.types.err; - } - } - hir::UnNot => { - oprnd_t = self.structurally_resolved_type(oprnd.span, - oprnd_t); - if !(oprnd_t.is_integral() || oprnd_t.sty == ty::TyBool) { - oprnd_t = self.check_user_unop("!", "not", - tcx.lang_items.not_trait(), - expr, &oprnd, oprnd_t, unop); - } - } - hir::UnNeg => { - oprnd_t = self.structurally_resolved_type(oprnd.span, - oprnd_t); - if !(oprnd_t.is_integral() || oprnd_t.is_fp()) { - oprnd_t = self.check_user_unop("-", "neg", - tcx.lang_items.neg_trait(), - expr, &oprnd, oprnd_t, unop); - } - } - } - } - self.write_ty(id, oprnd_t); - } - hir::ExprAddrOf(mutbl, ref oprnd) => { - let hint = expected.only_has_type(self).map_or(NoExpectation, |ty| { - match ty.sty { - ty::TyRef(_, ref mt) | ty::TyRawPtr(ref mt) => { - if self.tcx.expr_is_lval(&oprnd) { - // Lvalues may legitimately have unsized types. - // For example, dereferences of a fat pointer and - // the last field of a struct can be unsized. - ExpectHasType(mt.ty) - } else { - Expectation::rvalue_hint(self, mt.ty) - } - } - _ => NoExpectation - } - }); - let lvalue_pref = LvaluePreference::from_mutbl(mutbl); - self.check_expr_with_expectation_and_lvalue_pref(&oprnd, hint, lvalue_pref); - - let tm = ty::TypeAndMut { ty: self.expr_ty(&oprnd), mutbl: mutbl }; - let oprnd_t = if tm.ty.references_error() { - tcx.types.err - } else { - // Note: at this point, we cannot say what the best lifetime - // is to use for resulting pointer. We want to use the - // shortest lifetime possible so as to avoid spurious borrowck - // errors. Moreover, the longest lifetime will depend on the - // precise details of the value whose address is being taken - // (and how long it is valid), which we don't know yet until type - // inference is complete. - // - // Therefore, here we simply generate a region variable. The - // region inferencer will then select the ultimate value. - // Finally, borrowck is charged with guaranteeing that the - // value whose address was taken can actually be made to live - // as long as it needs to live. - let region = self.next_region_var(infer::AddrOfRegion(expr.span)); - tcx.mk_ref(tcx.mk_region(region), tm) - }; - self.write_ty(id, oprnd_t); - } - hir::ExprPath(ref maybe_qself, ref path) => { - let opt_self_ty = maybe_qself.as_ref().map(|qself| { - self.to_ty(&qself.ty) - }); - - let path_res = if let Some(&d) = tcx.def_map.borrow().get(&id) { - d - } else if let Some(hir::QSelf { position: 0, .. }) = *maybe_qself { - // Create some fake resolution that can't possibly be a type. - def::PathResolution { - base_def: Def::Mod(tcx.map.local_def_id(ast::CRATE_NODE_ID)), - depth: path.segments.len() - } - } else { - span_bug!(expr.span, "unbound path {:?}", expr) - }; - - if let Some((opt_ty, segments, def)) = - self.resolve_ty_and_def_ufcs(path_res, opt_self_ty, path, - expr.span, expr.id) { - if def != Def::Err { - let (scheme, predicates) = self.type_scheme_and_predicates_for_def(expr.span, - def); - self.instantiate_path(segments, scheme, &predicates, - opt_ty, def, expr.span, id); - } else { - self.set_tainted_by_errors(); - self.write_ty(id, self.tcx.types.err); - } - } - - // We always require that the type provided as the value for - // a type parameter outlives the moment of instantiation. - self.opt_node_ty_substs(expr.id, |item_substs| { - self.add_wf_bounds(&item_substs.substs, expr); - }); - } - hir::ExprInlineAsm(_, ref outputs, ref inputs) => { - for output in outputs { - self.check_expr(output); - } - for input in inputs { - self.check_expr(input); - } - self.write_nil(id); - } - hir::ExprBreak(_) => { self.write_ty(id, self.next_diverging_ty_var()); } - hir::ExprAgain(_) => { self.write_ty(id, self.next_diverging_ty_var()); } - hir::ExprRet(ref expr_opt) => { - match self.ret_ty { - ty::FnConverging(result_type) => { - if let Some(ref e) = *expr_opt { - self.check_expr_coercable_to_type(&e, result_type); - } else { - let eq_result = self.eq_types(false, - TypeOrigin::Misc(expr.span), - result_type, - tcx.mk_nil()) - // FIXME(#32730) propagate obligations - .map(|InferOk { obligations, .. }| assert!(obligations.is_empty())); - if eq_result.is_err() { - span_err!(tcx.sess, expr.span, E0069, - "`return;` in a function whose return type is not `()`"); - } - } - } - ty::FnDiverging => { - if let Some(ref e) = *expr_opt { - self.check_expr(&e); - } - span_err!(tcx.sess, expr.span, E0166, - "`return` in a function declared as diverging"); - } - } - self.write_ty(id, self.next_diverging_ty_var()); - } - hir::ExprAssign(ref lhs, ref rhs) => { - self.check_expr_with_lvalue_pref(&lhs, PreferMutLvalue); + /// Invariant: + /// If an expression has any sub-expressions that result in a type error, + /// inspecting that expression's type with `ty.references_error()` will return + /// true. Likewise, if an expression is known to diverge, inspecting its + /// type with `ty::type_is_bot` will return true (n.b.: since Rust is + /// strict, _|_ can appear in the type of an expression that does not, + /// itself, diverge: for example, fn() -> _|_.) + /// Note that inspecting a type's structure *directly* may expose the fact + /// that there are actually multiple representations for `TyError`, so avoid + /// that when err needs to be handled differently. + fn check_expr_with_expectation_and_lvalue_pref(&self, + expr: &'gcx hir::Expr, + expected: Expectation<'tcx>, + lvalue_pref: LvaluePreference) { + debug!(">> typechecking: expr={:?} expected={:?}", + expr, expected); let tcx = self.tcx; - if !tcx.expr_is_lval(&lhs) { - span_err!(tcx.sess, expr.span, E0070, - "invalid left-hand side expression"); - } - - let lhs_ty = self.expr_ty(&lhs); - self.check_expr_coercable_to_type(&rhs, lhs_ty); - let rhs_ty = self.expr_ty(&rhs); - - self.require_expr_have_sized_type(&lhs, traits::AssignmentLhsSized); - - if lhs_ty.references_error() || rhs_ty.references_error() { - self.write_error(id); - } else { - self.write_nil(id); - } - } - hir::ExprIf(ref cond, ref then_blk, ref opt_else_expr) => { - self.check_then_else(&cond, &then_blk, opt_else_expr.as_ref().map(|e| &**e), - id, expr.span, expected); - } - hir::ExprWhile(ref cond, ref body, _) => { - self.check_expr_has_type(&cond, tcx.types.bool); - self.check_block_no_value(&body); - let cond_ty = self.expr_ty(&cond); - let body_ty = self.node_ty(body.id); - if cond_ty.references_error() || body_ty.references_error() { - self.write_error(id); - } - else { - self.write_nil(id); - } - } - hir::ExprLoop(ref body, _) => { - self.check_block_no_value(&body); - if !may_break(tcx, expr.id, &body) { - self.write_ty(id, self.next_diverging_ty_var()); - } else { - self.write_nil(id); - } - } - hir::ExprMatch(ref discrim, ref arms, match_src) => { - self.check_match(expr, &discrim, arms, expected, match_src); - } - hir::ExprClosure(capture, ref decl, ref body, _) => { - self.check_expr_closure(expr, capture, &decl, &body, expected); - } - hir::ExprBlock(ref b) => { - self.check_block_with_expected(&b, expected); - self.write_ty(id, self.node_ty(b.id)); - } - hir::ExprCall(ref callee, ref args) => { - self.check_call(expr, &callee, &args[..], expected); - - // we must check that return type of called functions is WF: - let ret_ty = self.expr_ty(expr); - self.register_wf_obligation(ret_ty, expr.span, traits::MiscObligation); - } - hir::ExprMethodCall(name, ref tps, ref args) => { - self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref); - let arg_tys = args.iter().map(|a| self.expr_ty(&a)); - let args_err = arg_tys.fold(false, |rest_err, a| rest_err || a.references_error()); - if args_err { - self.write_error(id); + let id = expr.id; + match expr.node { + hir::ExprBox(ref subexpr) => { + let expected_inner = expected.to_option(self).map_or(NoExpectation, |ty| { + match ty.sty { + ty::TyBox(ty) => Expectation::rvalue_hint(self, ty), + _ => NoExpectation + } + }); + self.check_expr_with_expectation(subexpr, expected_inner); + let referent_ty = self.expr_ty(&subexpr); + self.write_ty(id, tcx.mk_box(referent_ty)); } - } - hir::ExprCast(ref e, ref t) => { - if let hir::TyFixedLengthVec(_, ref count_expr) = t.node { - self.check_expr_with_hint(&count_expr, tcx.types.usize); - } - // Find the type of `e`. Supply hints based on the type we are casting to, - // if appropriate. - let t_cast = self.to_ty(t); - let t_cast = self.resolve_type_vars_if_possible(&t_cast); - self.check_expr_with_expectation(e, ExpectCastableToType(t_cast)); - let t_expr = self.expr_ty(e); - let t_cast = self.resolve_type_vars_if_possible(&t_cast); - - // Eagerly check for some obvious errors. - if t_expr.references_error() || t_cast.references_error() { - self.write_error(id); - } else { - // Write a type for the whole expression, assuming everything is going - // to work out Ok. - self.write_ty(id, t_cast); - - // Defer other checks until we're done type checking. - let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); - match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) { - Ok(cast_check) => { - deferred_cast_checks.push(cast_check); + hir::ExprLit(ref lit) => { + let typ = self.check_lit(&lit, expected); + self.write_ty(id, typ); + } + hir::ExprBinary(op, ref lhs, ref rhs) => { + self.check_binop(expr, op, lhs, rhs); + } + hir::ExprAssignOp(op, ref lhs, ref rhs) => { + self.check_binop_assign(expr, op, lhs, rhs); + } + hir::ExprUnary(unop, ref oprnd) => { + let expected_inner = match unop { + hir::UnNot | hir::UnNeg => { + expected } - Err(ErrorReported) => { - self.write_error(id); + hir::UnDeref => { + NoExpectation } - } - } - } - hir::ExprType(ref e, ref t) => { - let typ = self.to_ty(&t); - self.check_expr_eq_type(&e, typ); - self.write_ty(id, typ); - } - hir::ExprVec(ref args) => { - let uty = expected.to_option(self).and_then(|uty| { - match uty.sty { - ty::TyArray(ty, _) | ty::TySlice(ty) => Some(ty), - _ => None - } - }); - - let mut unified = self.next_ty_var(); - let coerce_to = uty.unwrap_or(unified); - - for (i, e) in args.iter().enumerate() { - self.check_expr_with_hint(e, coerce_to); - let e_ty = self.expr_ty(e); - let origin = TypeOrigin::Misc(e.span); - - // Special-case the first element, as it has no "previous expressions". - let result = if i == 0 { - self.try_coerce(e, coerce_to) - } else { - let prev_elems = || args[..i].iter().map(|e| &**e); - self.try_find_coercion_lub(origin, prev_elems, unified, e) }; + let lvalue_pref = match unop { + hir::UnDeref => lvalue_pref, + _ => NoPreference + }; + self.check_expr_with_expectation_and_lvalue_pref(&oprnd, + expected_inner, + lvalue_pref); + let mut oprnd_t = self.expr_ty(&oprnd); - match result { - Ok(ty) => unified = ty, - Err(e) => { - self.report_mismatched_types(origin, unified, e_ty, e); + if !oprnd_t.references_error() { + match unop { + hir::UnDeref => { + oprnd_t = self.structurally_resolved_type(expr.span, oprnd_t); + + if let Some(mt) = oprnd_t.builtin_deref(true, NoPreference) { + oprnd_t = mt.ty; + } else if let Some(method) = self.try_overloaded_deref( + expr.span, Some(&oprnd), oprnd_t, lvalue_pref) { + oprnd_t = self.make_overloaded_lvalue_return_type(method).ty; + self.tables.borrow_mut().method_map.insert(MethodCall::expr(expr.id), + method); + } else { + self.type_error_message(expr.span, |actual| { + format!("type `{}` cannot be \ + dereferenced", actual) + }, oprnd_t, None); + oprnd_t = tcx.types.err; + } + } + hir::UnNot => { + oprnd_t = self.structurally_resolved_type(oprnd.span, + oprnd_t); + if !(oprnd_t.is_integral() || oprnd_t.sty == ty::TyBool) { + oprnd_t = self.check_user_unop("!", "not", + tcx.lang_items.not_trait(), + expr, &oprnd, oprnd_t, unop); + } + } + hir::UnNeg => { + oprnd_t = self.structurally_resolved_type(oprnd.span, + oprnd_t); + if !(oprnd_t.is_integral() || oprnd_t.is_fp()) { + oprnd_t = self.check_user_unop("-", "neg", + tcx.lang_items.neg_trait(), + expr, &oprnd, oprnd_t, unop); + } + } } } - } - self.write_ty(id, tcx.mk_array(unified, args.len())); - } - hir::ExprRepeat(ref element, ref count_expr) => { - self.check_expr_has_type(&count_expr, tcx.types.usize); - let count = eval_repeat_count(self.tcx.global_tcx(), &count_expr); + self.write_ty(id, oprnd_t); + } + hir::ExprAddrOf(mutbl, ref oprnd) => { + let hint = expected.only_has_type(self).map_or(NoExpectation, |ty| { + match ty.sty { + ty::TyRef(_, ref mt) | ty::TyRawPtr(ref mt) => { + if self.tcx.expr_is_lval(&oprnd) { + // Lvalues may legitimately have unsized types. + // For example, dereferences of a fat pointer and + // the last field of a struct can be unsized. + ExpectHasType(mt.ty) + } else { + Expectation::rvalue_hint(self, mt.ty) + } + } + _ => NoExpectation + } + }); + let lvalue_pref = LvaluePreference::from_mutbl(mutbl); + self.check_expr_with_expectation_and_lvalue_pref(&oprnd, hint, lvalue_pref); - let uty = match expected { - ExpectHasType(uty) => { + let tm = ty::TypeAndMut { ty: self.expr_ty(&oprnd), mutbl: mutbl }; + let oprnd_t = if tm.ty.references_error() { + tcx.types.err + } else { + // Note: at this point, we cannot say what the best lifetime + // is to use for resulting pointer. We want to use the + // shortest lifetime possible so as to avoid spurious borrowck + // errors. Moreover, the longest lifetime will depend on the + // precise details of the value whose address is being taken + // (and how long it is valid), which we don't know yet until type + // inference is complete. + // + // Therefore, here we simply generate a region variable. The + // region inferencer will then select the ultimate value. + // Finally, borrowck is charged with guaranteeing that the + // value whose address was taken can actually be made to live + // as long as it needs to live. + let region = self.next_region_var(infer::AddrOfRegion(expr.span)); + tcx.mk_ref(tcx.mk_region(region), tm) + }; + self.write_ty(id, oprnd_t); + } + hir::ExprPath(ref maybe_qself, ref path) => { + let opt_self_ty = maybe_qself.as_ref().map(|qself| { + self.to_ty(&qself.ty) + }); + + let path_res = if let Some(&d) = tcx.def_map.borrow().get(&id) { + d + } else if let Some(hir::QSelf { position: 0, .. }) = *maybe_qself { + // Create some fake resolution that can't possibly be a type. + def::PathResolution { + base_def: Def::Mod(tcx.map.local_def_id(ast::CRATE_NODE_ID)), + depth: path.segments.len() + } + } else { + span_bug!(expr.span, "unbound path {:?}", expr) + }; + + if let Some((opt_ty, segments, def)) = + self.resolve_ty_and_def_ufcs(path_res, opt_self_ty, path, + expr.span, expr.id) { + if def != Def::Err { + let (scheme, predicates) = self.type_scheme_and_predicates_for_def(expr.span, + def); + self.instantiate_path(segments, scheme, &predicates, + opt_ty, def, expr.span, id); + } else { + self.set_tainted_by_errors(); + self.write_ty(id, self.tcx.types.err); + } + } + + // We always require that the type provided as the value for + // a type parameter outlives the moment of instantiation. + self.opt_node_ty_substs(expr.id, |item_substs| { + self.add_wf_bounds(&item_substs.substs, expr); + }); + } + hir::ExprInlineAsm(_, ref outputs, ref inputs) => { + for output in outputs { + self.check_expr(output); + } + for input in inputs { + self.check_expr(input); + } + self.write_nil(id); + } + hir::ExprBreak(_) => { self.write_ty(id, self.next_diverging_ty_var()); } + hir::ExprAgain(_) => { self.write_ty(id, self.next_diverging_ty_var()); } + hir::ExprRet(ref expr_opt) => { + match self.ret_ty { + ty::FnConverging(result_type) => { + if let Some(ref e) = *expr_opt { + self.check_expr_coercable_to_type(&e, result_type); + } else { + let eq_result = self.eq_types(false, + TypeOrigin::Misc(expr.span), + result_type, + tcx.mk_nil()) + // FIXME(#32730) propagate obligations + .map(|InferOk { obligations, .. }| assert!(obligations.is_empty())); + if eq_result.is_err() { + span_err!(tcx.sess, expr.span, E0069, + "`return;` in a function whose return type is not `()`"); + } + } + } + ty::FnDiverging => { + if let Some(ref e) = *expr_opt { + self.check_expr(&e); + } + span_err!(tcx.sess, expr.span, E0166, + "`return` in a function declared as diverging"); + } + } + self.write_ty(id, self.next_diverging_ty_var()); + } + hir::ExprAssign(ref lhs, ref rhs) => { + self.check_expr_with_lvalue_pref(&lhs, PreferMutLvalue); + + let tcx = self.tcx; + if !tcx.expr_is_lval(&lhs) { + span_err!(tcx.sess, expr.span, E0070, + "invalid left-hand side expression"); + } + + let lhs_ty = self.expr_ty(&lhs); + self.check_expr_coercable_to_type(&rhs, lhs_ty); + let rhs_ty = self.expr_ty(&rhs); + + self.require_expr_have_sized_type(&lhs, traits::AssignmentLhsSized); + + if lhs_ty.references_error() || rhs_ty.references_error() { + self.write_error(id); + } else { + self.write_nil(id); + } + } + hir::ExprIf(ref cond, ref then_blk, ref opt_else_expr) => { + self.check_then_else(&cond, &then_blk, opt_else_expr.as_ref().map(|e| &**e), + id, expr.span, expected); + } + hir::ExprWhile(ref cond, ref body, _) => { + self.check_expr_has_type(&cond, tcx.types.bool); + self.check_block_no_value(&body); + let cond_ty = self.expr_ty(&cond); + let body_ty = self.node_ty(body.id); + if cond_ty.references_error() || body_ty.references_error() { + self.write_error(id); + } + else { + self.write_nil(id); + } + } + hir::ExprLoop(ref body, _) => { + self.check_block_no_value(&body); + if !may_break(tcx, expr.id, &body) { + self.write_ty(id, self.next_diverging_ty_var()); + } else { + self.write_nil(id); + } + } + hir::ExprMatch(ref discrim, ref arms, match_src) => { + self.check_match(expr, &discrim, arms, expected, match_src); + } + hir::ExprClosure(capture, ref decl, ref body, _) => { + self.check_expr_closure(expr, capture, &decl, &body, expected); + } + hir::ExprBlock(ref b) => { + self.check_block_with_expected(&b, expected); + self.write_ty(id, self.node_ty(b.id)); + } + hir::ExprCall(ref callee, ref args) => { + self.check_call(expr, &callee, &args[..], expected); + + // we must check that return type of called functions is WF: + let ret_ty = self.expr_ty(expr); + self.register_wf_obligation(ret_ty, expr.span, traits::MiscObligation); + } + hir::ExprMethodCall(name, ref tps, ref args) => { + self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref); + let arg_tys = args.iter().map(|a| self.expr_ty(&a)); + let args_err = arg_tys.fold(false, |rest_err, a| rest_err || a.references_error()); + if args_err { + self.write_error(id); + } + } + hir::ExprCast(ref e, ref t) => { + if let hir::TyFixedLengthVec(_, ref count_expr) = t.node { + self.check_expr_with_hint(&count_expr, tcx.types.usize); + } + + // Find the type of `e`. Supply hints based on the type we are casting to, + // if appropriate. + let t_cast = self.to_ty(t); + let t_cast = self.resolve_type_vars_if_possible(&t_cast); + self.check_expr_with_expectation(e, ExpectCastableToType(t_cast)); + let t_expr = self.expr_ty(e); + let t_cast = self.resolve_type_vars_if_possible(&t_cast); + + // Eagerly check for some obvious errors. + if t_expr.references_error() || t_cast.references_error() { + self.write_error(id); + } else { + // Write a type for the whole expression, assuming everything is going + // to work out Ok. + self.write_ty(id, t_cast); + + // Defer other checks until we're done type checking. + let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); + match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) { + Ok(cast_check) => { + deferred_cast_checks.push(cast_check); + } + Err(ErrorReported) => { + self.write_error(id); + } + } + } + } + hir::ExprType(ref e, ref t) => { + let typ = self.to_ty(&t); + self.check_expr_eq_type(&e, typ); + self.write_ty(id, typ); + } + hir::ExprVec(ref args) => { + let uty = expected.to_option(self).and_then(|uty| { match uty.sty { ty::TyArray(ty, _) | ty::TySlice(ty) => Some(ty), _ => None } - } - _ => None - }; + }); - let (element_ty, t) = match uty { - Some(uty) => { - self.check_expr_coercable_to_type(&element, uty); - (uty, uty) - } - None => { - let t: Ty = self.next_ty_var(); - self.check_expr_has_type(&element, t); - (self.expr_ty(&element), t) - } - }; + let mut unified = self.next_ty_var(); + let coerce_to = uty.unwrap_or(unified); - if count > 1 { - // For [foo, ..n] where n > 1, `foo` must have - // Copy type: - self.require_type_meets(t, expr.span, traits::RepeatVec, ty::BoundCopy); - } + for (i, e) in args.iter().enumerate() { + self.check_expr_with_hint(e, coerce_to); + let e_ty = self.expr_ty(e); + let origin = TypeOrigin::Misc(e.span); - if element_ty.references_error() { - self.write_error(id); - } else { - let t = tcx.mk_array(t, count); - self.write_ty(id, t); - } - } - hir::ExprTup(ref elts) => { - let flds = expected.only_has_type(self).and_then(|ty| { - match ty.sty { - ty::TyTuple(ref flds) => Some(&flds[..]), - _ => None - } - }); - let mut err_field = false; + // Special-case the first element, as it has no "previous expressions". + let result = if i == 0 { + self.try_coerce(e, coerce_to) + } else { + let prev_elems = || args[..i].iter().map(|e| &**e); + self.try_find_coercion_lub(origin, prev_elems, unified, e) + }; - let elt_ts = elts.iter().enumerate().map(|(i, e)| { - let t = match flds { - Some(ref fs) if i < fs.len() => { - let ety = fs[i]; - self.check_expr_coercable_to_type(&e, ety); - ety + match result { + Ok(ty) => unified = ty, + Err(e) => { + self.report_mismatched_types(origin, unified, e_ty, e); + } } - _ => { - self.check_expr_with_expectation(&e, NoExpectation); - self.expr_ty(&e) + } + self.write_ty(id, tcx.mk_array(unified, args.len())); + } + hir::ExprRepeat(ref element, ref count_expr) => { + self.check_expr_has_type(&count_expr, tcx.types.usize); + let count = eval_repeat_count(self.tcx.global_tcx(), &count_expr); + + let uty = match expected { + ExpectHasType(uty) => { + match uty.sty { + ty::TyArray(ty, _) | ty::TySlice(ty) => Some(ty), + _ => None + } + } + _ => None + }; + + let (element_ty, t) = match uty { + Some(uty) => { + self.check_expr_coercable_to_type(&element, uty); + (uty, uty) + } + None => { + let t: Ty = self.next_ty_var(); + self.check_expr_has_type(&element, t); + (self.expr_ty(&element), t) } }; - err_field = err_field || t.references_error(); - t - }).collect(); - if err_field { - self.write_error(id); - } else { - let typ = tcx.mk_tup(elt_ts); - self.write_ty(id, typ); - } - } - hir::ExprStruct(ref path, ref fields, ref base_expr) => { - self.check_expr_struct(expr, path, fields, base_expr); - self.require_expr_have_sized_type(expr, traits::StructInitializerSized); - } - hir::ExprField(ref base, ref field) => { - self.check_field(expr, lvalue_pref, &base, field); - } - hir::ExprTupField(ref base, idx) => { - self.check_tup_field(expr, lvalue_pref, &base, idx); - } - hir::ExprIndex(ref base, ref idx) => { - self.check_expr_with_lvalue_pref(&base, lvalue_pref); - self.check_expr(&idx); + if count > 1 { + // For [foo, ..n] where n > 1, `foo` must have + // Copy type: + self.require_type_meets(t, expr.span, traits::RepeatVec, ty::BoundCopy); + } - let base_t = self.expr_ty(&base); - let idx_t = self.expr_ty(&idx); + if element_ty.references_error() { + self.write_error(id); + } else { + let t = tcx.mk_array(t, count); + self.write_ty(id, t); + } + } + hir::ExprTup(ref elts) => { + let flds = expected.only_has_type(self).and_then(|ty| { + match ty.sty { + ty::TyTuple(ref flds) => Some(&flds[..]), + _ => None + } + }); + let mut err_field = false; - if base_t.references_error() { - self.write_ty(id, base_t); - } else if idx_t.references_error() { - self.write_ty(id, idx_t); - } else { - let base_t = self.structurally_resolved_type(expr.span, base_t); - match self.lookup_indexing(expr, base, base_t, idx_t, lvalue_pref) { - Some((index_ty, element_ty)) => { - let idx_expr_ty = self.expr_ty(idx); - self.demand_eqtype(expr.span, index_ty, idx_expr_ty); - self.write_ty(id, element_ty); - } - None => { - self.check_expr_has_type(&idx, self.tcx.types.err); - let mut err = self.type_error_struct( - expr.span, - |actual| { - format!("cannot index a value of type `{}`", - actual) - }, - base_t, - None); - // Try to give some advice about indexing tuples. - if let ty::TyTuple(_) = base_t.sty { - let mut needs_note = true; - // If the index is an integer, we can show the actual - // fixed expression: - if let hir::ExprLit(ref lit) = idx.node { - if let ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) = lit.node { - let snip = tcx.sess.codemap().span_to_snippet(base.span); - if let Ok(snip) = snip { - err.span_suggestion(expr.span, - "to access tuple elements, use tuple \ - indexing syntax as shown", - format!("{}.{}", snip, i)); - needs_note = false; + let elt_ts = elts.iter().enumerate().map(|(i, e)| { + let t = match flds { + Some(ref fs) if i < fs.len() => { + let ety = fs[i]; + self.check_expr_coercable_to_type(&e, ety); + ety + } + _ => { + self.check_expr_with_expectation(&e, NoExpectation); + self.expr_ty(&e) + } + }; + err_field = err_field || t.references_error(); + t + }).collect(); + if err_field { + self.write_error(id); + } else { + let typ = tcx.mk_tup(elt_ts); + self.write_ty(id, typ); + } + } + hir::ExprStruct(ref path, ref fields, ref base_expr) => { + self.check_expr_struct(expr, path, fields, base_expr); + + self.require_expr_have_sized_type(expr, traits::StructInitializerSized); + } + hir::ExprField(ref base, ref field) => { + self.check_field(expr, lvalue_pref, &base, field); + } + hir::ExprTupField(ref base, idx) => { + self.check_tup_field(expr, lvalue_pref, &base, idx); + } + hir::ExprIndex(ref base, ref idx) => { + self.check_expr_with_lvalue_pref(&base, lvalue_pref); + self.check_expr(&idx); + + let base_t = self.expr_ty(&base); + let idx_t = self.expr_ty(&idx); + + if base_t.references_error() { + self.write_ty(id, base_t); + } else if idx_t.references_error() { + self.write_ty(id, idx_t); + } else { + let base_t = self.structurally_resolved_type(expr.span, base_t); + match self.lookup_indexing(expr, base, base_t, idx_t, lvalue_pref) { + Some((index_ty, element_ty)) => { + let idx_expr_ty = self.expr_ty(idx); + self.demand_eqtype(expr.span, index_ty, idx_expr_ty); + self.write_ty(id, element_ty); + } + None => { + self.check_expr_has_type(&idx, self.tcx.types.err); + let mut err = self.type_error_struct( + expr.span, + |actual| { + format!("cannot index a value of type `{}`", + actual) + }, + base_t, + None); + // Try to give some advice about indexing tuples. + if let ty::TyTuple(_) = base_t.sty { + let mut needs_note = true; + // If the index is an integer, we can show the actual + // fixed expression: + if let hir::ExprLit(ref lit) = idx.node { + if let ast::LitKind::Int(i, + ast::LitIntType::Unsuffixed) = lit.node { + let snip = tcx.sess.codemap().span_to_snippet(base.span); + if let Ok(snip) = snip { + err.span_suggestion(expr.span, + "to access tuple elements, \ + use tuple indexing syntax \ + as shown", + format!("{}.{}", snip, i)); + needs_note = false; + } } } + if needs_note { + err.help("to access tuple elements, use tuple indexing \ + syntax (e.g. `tuple.0`)"); + } } - if needs_note { - err.help("to access tuple elements, use tuple indexing \ - syntax (e.g. `tuple.0`)"); - } + err.emit(); + self.write_ty(id, self.tcx().types.err); } - err.emit(); - self.write_ty(id, self.tcx().types.err); } } - } - } + } + } + + debug!("type of expr({}) {} is...", expr.id, + pprust::expr_to_string(expr)); + debug!("... {:?}, expected is {:?}", + self.expr_ty(expr), + expected); } - debug!("type of expr({}) {} is...", expr.id, - pprust::expr_to_string(expr)); - debug!("... {:?}, expected is {:?}", - self.expr_ty(expr), - expected); -} + pub fn resolve_ty_and_def_ufcs<'b>(&self, + path_res: def::PathResolution, + opt_self_ty: Option>, + path: &'b hir::Path, + span: Span, + node_id: ast::NodeId) + -> Option<(Option>, &'b [hir::PathSegment], Def)> + { -pub fn resolve_ty_and_def_ufcs<'b>(&self, - path_res: def::PathResolution, - opt_self_ty: Option>, - path: &'b hir::Path, - span: Span, - node_id: ast::NodeId) - -> Option<(Option>, &'b [hir::PathSegment], Def)> -{ - - // If fully resolved already, we don't have to do anything. - if path_res.depth == 0 { - Some((opt_self_ty, &path.segments, path_res.base_def)) - } else { - let mut def = path_res.base_def; - let ty_segments = path.segments.split_last().unwrap().1; - let base_ty_end = path.segments.len() - path_res.depth; - let ty = AstConv::finish_resolving_def_to_ty(self, self, span, - PathParamMode::Optional, - &mut def, - opt_self_ty, - &ty_segments[..base_ty_end], - &ty_segments[base_ty_end..]); - let item_segment = path.segments.last().unwrap(); - let item_name = item_segment.identifier.name; - let def = match self.resolve_ufcs(span, item_name, ty, node_id) { - Ok(def) => Some(def), - Err(error) => { - let def = match error { - method::MethodError::PrivateMatch(def) => Some(def), - _ => None, - }; - if item_name != keywords::Invalid.name() { - self.report_method_error(span, ty, item_name, None, error); + // If fully resolved already, we don't have to do anything. + if path_res.depth == 0 { + Some((opt_self_ty, &path.segments, path_res.base_def)) + } else { + let mut def = path_res.base_def; + let ty_segments = path.segments.split_last().unwrap().1; + let base_ty_end = path.segments.len() - path_res.depth; + let ty = AstConv::finish_resolving_def_to_ty(self, self, span, + PathParamMode::Optional, + &mut def, + opt_self_ty, + &ty_segments[..base_ty_end], + &ty_segments[base_ty_end..]); + let item_segment = path.segments.last().unwrap(); + let item_name = item_segment.identifier.name; + let def = match self.resolve_ufcs(span, item_name, ty, node_id) { + Ok(def) => Some(def), + Err(error) => { + let def = match error { + method::MethodError::PrivateMatch(def) => Some(def), + _ => None, + }; + if item_name != keywords::Invalid.name() { + self.report_method_error(span, ty, item_name, None, error); + } + def } - def + }; + + if let Some(def) = def { + // Write back the new resolution. + self.tcx().def_map.borrow_mut().insert(node_id, def::PathResolution { + base_def: def, + depth: 0, + }); + Some((Some(ty), slice::ref_slice(item_segment), def)) + } else { + self.write_error(node_id); + None } + } + } + + pub fn check_decl_initializer(&self, + local: &'gcx hir::Local, + init: &'gcx hir::Expr) + { + let ref_bindings = self.tcx.pat_contains_ref_binding(&local.pat); + + let local_ty = self.local_ty(init.span, local.id); + if let Some(m) = ref_bindings { + // Somewhat subtle: if we have a `ref` binding in the pattern, + // we want to avoid introducing coercions for the RHS. This is + // both because it helps preserve sanity and, in the case of + // ref mut, for soundness (issue #23116). In particular, in + // the latter case, we need to be clear that the type of the + // referent for the reference that results is *equal to* the + // type of the lvalue it is referencing, and not some + // supertype thereof. + self.check_expr_with_lvalue_pref(init, LvaluePreference::from_mutbl(m)); + let init_ty = self.expr_ty(init); + self.demand_eqtype(init.span, init_ty, local_ty); + } else { + self.check_expr_coercable_to_type(init, local_ty) + }; + } + + pub fn check_decl_local(&self, local: &'gcx hir::Local) { + let tcx = self.tcx; + + let t = self.local_ty(local.span, local.id); + self.write_ty(local.id, t); + + if let Some(ref init) = local.init { + self.check_decl_initializer(local, &init); + let init_ty = self.expr_ty(&init); + if init_ty.references_error() { + self.write_ty(local.id, init_ty); + } + } + + let pcx = PatCtxt { + fcx: self, + map: pat_id_map(&tcx.def_map, &local.pat), + }; + pcx.check_pat(&local.pat, t); + let pat_ty = self.node_ty(local.pat.id); + if pat_ty.references_error() { + self.write_ty(local.id, pat_ty); + } + } + + pub fn check_stmt(&self, stmt: &'gcx hir::Stmt) { + let node_id; + let mut saw_bot = false; + let mut saw_err = false; + match stmt.node { + hir::StmtDecl(ref decl, id) => { + node_id = id; + match decl.node { + hir::DeclLocal(ref l) => { + self.check_decl_local(&l); + let l_t = self.node_ty(l.id); + saw_bot = saw_bot || self.type_var_diverges(l_t); + saw_err = saw_err || l_t.references_error(); + } + hir::DeclItem(_) => {/* ignore for now */ } + } + } + hir::StmtExpr(ref expr, id) => { + node_id = id; + // Check with expected type of () + self.check_expr_has_type(&expr, self.tcx.mk_nil()); + let expr_ty = self.expr_ty(&expr); + saw_bot = saw_bot || self.type_var_diverges(expr_ty); + saw_err = saw_err || expr_ty.references_error(); + } + hir::StmtSemi(ref expr, id) => { + node_id = id; + self.check_expr(&expr); + let expr_ty = self.expr_ty(&expr); + saw_bot |= self.type_var_diverges(expr_ty); + saw_err |= expr_ty.references_error(); + } + } + if saw_bot { + self.write_ty(node_id, self.next_diverging_ty_var()); + } + else if saw_err { + self.write_error(node_id); + } + else { + self.write_nil(node_id) + } + } + + pub fn check_block_no_value(&self, blk: &'gcx hir::Block) { + self.check_block_with_expected(blk, ExpectHasType(self.tcx.mk_nil())); + let blkty = self.node_ty(blk.id); + if blkty.references_error() { + self.write_error(blk.id); + } else { + let nilty = self.tcx.mk_nil(); + self.demand_suptype(blk.span, nilty, blkty); + } + } + + fn check_block_with_expected(&self, + blk: &'gcx hir::Block, + expected: Expectation<'tcx>) { + let prev = { + let mut fcx_ps = self.ps.borrow_mut(); + let unsafety_state = fcx_ps.recurse(blk); + replace(&mut *fcx_ps, unsafety_state) }; - if let Some(def) = def { - // Write back the new resolution. - self.tcx().def_map.borrow_mut().insert(node_id, def::PathResolution { - base_def: def, - depth: 0, - }); - Some((Some(ty), slice::ref_slice(item_segment), def)) - } else { - self.write_error(node_id); - None - } - } -} - -pub fn check_decl_initializer(&self, - local: &'gcx hir::Local, - init: &'gcx hir::Expr) -{ - let ref_bindings = self.tcx.pat_contains_ref_binding(&local.pat); - - let local_ty = self.local_ty(init.span, local.id); - if let Some(m) = ref_bindings { - // Somewhat subtle: if we have a `ref` binding in the pattern, - // we want to avoid introducing coercions for the RHS. This is - // both because it helps preserve sanity and, in the case of - // ref mut, for soundness (issue #23116). In particular, in - // the latter case, we need to be clear that the type of the - // referent for the reference that results is *equal to* the - // type of the lvalue it is referencing, and not some - // supertype thereof. - self.check_expr_with_lvalue_pref(init, LvaluePreference::from_mutbl(m)); - let init_ty = self.expr_ty(init); - self.demand_eqtype(init.span, init_ty, local_ty); - } else { - self.check_expr_coercable_to_type(init, local_ty) - }; -} - -pub fn check_decl_local(&self, local: &'gcx hir::Local) { - let tcx = self.tcx; - - let t = self.local_ty(local.span, local.id); - self.write_ty(local.id, t); - - if let Some(ref init) = local.init { - self.check_decl_initializer(local, &init); - let init_ty = self.expr_ty(&init); - if init_ty.references_error() { - self.write_ty(local.id, init_ty); - } - } - - let pcx = PatCtxt { - fcx: self, - map: pat_id_map(&tcx.def_map, &local.pat), - }; - pcx.check_pat(&local.pat, t); - let pat_ty = self.node_ty(local.pat.id); - if pat_ty.references_error() { - self.write_ty(local.id, pat_ty); - } -} - -pub fn check_stmt(&self, stmt: &'gcx hir::Stmt) { - let node_id; - let mut saw_bot = false; - let mut saw_err = false; - match stmt.node { - hir::StmtDecl(ref decl, id) => { - node_id = id; - match decl.node { - hir::DeclLocal(ref l) => { - self.check_decl_local(&l); - let l_t = self.node_ty(l.id); - saw_bot = saw_bot || self.type_var_diverges(l_t); - saw_err = saw_err || l_t.references_error(); - } - hir::DeclItem(_) => {/* ignore for now */ } - } - } - hir::StmtExpr(ref expr, id) => { - node_id = id; - // Check with expected type of () - self.check_expr_has_type(&expr, self.tcx.mk_nil()); - let expr_ty = self.expr_ty(&expr); - saw_bot = saw_bot || self.type_var_diverges(expr_ty); - saw_err = saw_err || expr_ty.references_error(); - } - hir::StmtSemi(ref expr, id) => { - node_id = id; - self.check_expr(&expr); - let expr_ty = self.expr_ty(&expr); - saw_bot |= self.type_var_diverges(expr_ty); - saw_err |= expr_ty.references_error(); - } - } - if saw_bot { - self.write_ty(node_id, self.next_diverging_ty_var()); - } - else if saw_err { - self.write_error(node_id); - } - else { - self.write_nil(node_id) - } -} - -pub fn check_block_no_value(&self, blk: &'gcx hir::Block) { - self.check_block_with_expected(blk, ExpectHasType(self.tcx.mk_nil())); - let blkty = self.node_ty(blk.id); - if blkty.references_error() { - self.write_error(blk.id); - } else { - let nilty = self.tcx.mk_nil(); - self.demand_suptype(blk.span, nilty, blkty); - } -} - -fn check_block_with_expected(&self, - blk: &'gcx hir::Block, - expected: Expectation<'tcx>) { - let prev = { - let mut fcx_ps = self.ps.borrow_mut(); - let unsafety_state = fcx_ps.recurse(blk); - replace(&mut *fcx_ps, unsafety_state) - }; - - let mut warned = false; - let mut any_diverges = false; - let mut any_err = false; - for s in &blk.stmts { - self.check_stmt(s); - let s_id = s.node.id(); - let s_ty = self.node_ty(s_id); - if any_diverges && !warned && match s.node { - hir::StmtDecl(ref decl, _) => { - match decl.node { - hir::DeclLocal(_) => true, - _ => false, + let mut warned = false; + let mut any_diverges = false; + let mut any_err = false; + for s in &blk.stmts { + self.check_stmt(s); + let s_id = s.node.id(); + let s_ty = self.node_ty(s_id); + if any_diverges && !warned && match s.node { + hir::StmtDecl(ref decl, _) => { + match decl.node { + hir::DeclLocal(_) => true, + _ => false, + } } - } - hir::StmtExpr(_, _) | hir::StmtSemi(_, _) => true, - } { - self.tcx - .sess - .add_lint(lint::builtin::UNREACHABLE_CODE, - s_id, - s.span, - "unreachable statement".to_string()); - warned = true; - } - any_diverges = any_diverges || self.type_var_diverges(s_ty); - any_err = any_err || s_ty.references_error(); - } - match blk.expr { - None => if any_err { - self.write_error(blk.id); - } else if any_diverges { - self.write_ty(blk.id, self.next_diverging_ty_var()); - } else { - self.write_nil(blk.id); - }, - Some(ref e) => { - if any_diverges && !warned { + hir::StmtExpr(_, _) | hir::StmtSemi(_, _) => true, + } { self.tcx .sess .add_lint(lint::builtin::UNREACHABLE_CODE, - e.id, - e.span, - "unreachable expression".to_string()); + s_id, + s.span, + "unreachable statement".to_string()); + warned = true; } - let ety = match expected { - ExpectHasType(ety) => { - self.check_expr_coercable_to_type(&e, ety); - ety - } - _ => { - self.check_expr_with_expectation(&e, expected); - self.expr_ty(&e) - } - }; - - if any_err { + any_diverges = any_diverges || self.type_var_diverges(s_ty); + any_err = any_err || s_ty.references_error(); + } + match blk.expr { + None => if any_err { self.write_error(blk.id); } else if any_diverges { self.write_ty(blk.id, self.next_diverging_ty_var()); } else { - self.write_ty(blk.id, ety); + self.write_nil(blk.id); + }, + Some(ref e) => { + if any_diverges && !warned { + self.tcx + .sess + .add_lint(lint::builtin::UNREACHABLE_CODE, + e.id, + e.span, + "unreachable expression".to_string()); + } + let ety = match expected { + ExpectHasType(ety) => { + self.check_expr_coercable_to_type(&e, ety); + ety + } + _ => { + self.check_expr_with_expectation(&e, expected); + self.expr_ty(&e) + } + }; + + if any_err { + self.write_error(blk.id); + } else if any_diverges { + self.write_ty(blk.id, self.next_diverging_ty_var()); + } else { + self.write_ty(blk.id, ety); + } } - } - }; + }; - *self.ps.borrow_mut() = prev; -} + *self.ps.borrow_mut() = prev; + } -fn check_const_with_ty(&self, - _: Span, - e: &'gcx hir::Expr, - declty: Ty<'tcx>) { - // Gather locals in statics (because of block expressions). - // This is technically unnecessary because locals in static items are forbidden, - // but prevents type checking from blowing up before const checking can properly - // emit an error. - GatherLocalsVisitor { fcx: self }.visit_expr(e); + fn check_const_with_ty(&self, + _: Span, + e: &'gcx hir::Expr, + declty: Ty<'tcx>) { + // Gather locals in statics (because of block expressions). + // This is technically unnecessary because locals in static items are forbidden, + // but prevents type checking from blowing up before const checking can properly + // emit an error. + GatherLocalsVisitor { fcx: self }.visit_expr(e); - self.check_expr_coercable_to_type(e, declty); + self.check_expr_coercable_to_type(e, declty); - self.select_all_obligations_and_apply_defaults(); - self.closure_analyze_const(e); - self.select_obligations_where_possible(); - self.check_casts(); - self.select_all_obligations_or_error(); + self.select_all_obligations_and_apply_defaults(); + self.closure_analyze_const(e); + self.select_obligations_where_possible(); + self.check_casts(); + self.select_all_obligations_or_error(); - self.regionck_expr(e); - self.resolve_type_vars_in_expr(e); -} + self.regionck_expr(e); + self.resolve_type_vars_in_expr(e); + } -// Returns the type parameter count and the type for the given definition. -fn type_scheme_and_predicates_for_def(&self, - sp: Span, - defn: Def) - -> (TypeScheme<'tcx>, GenericPredicates<'tcx>) { - match defn { - Def::Local(_, nid) | Def::Upvar(_, nid, _, _) => { - let typ = self.local_ty(sp, nid); - (ty::TypeScheme { generics: ty::Generics::empty(), ty: typ }, - ty::GenericPredicates::empty()) - } - Def::Fn(id) | Def::Method(id) | - Def::Static(id, _) | Def::Variant(_, id) | - Def::Struct(id) | Def::Const(id) | Def::AssociatedConst(id) => { - (self.tcx.lookup_item_type(id), self.tcx.lookup_predicates(id)) - } - Def::Trait(_) | - Def::Enum(..) | - Def::TyAlias(..) | - Def::AssociatedTy(..) | - Def::PrimTy(_) | - Def::TyParam(..) | - Def::Mod(..) | - Def::ForeignMod(..) | - Def::Label(..) | - Def::SelfTy(..) | - Def::Err => { - span_bug!(sp, "expected value, found {:?}", defn); + // Returns the type parameter count and the type for the given definition. + fn type_scheme_and_predicates_for_def(&self, + sp: Span, + defn: Def) + -> (TypeScheme<'tcx>, GenericPredicates<'tcx>) { + match defn { + Def::Local(_, nid) | Def::Upvar(_, nid, _, _) => { + let typ = self.local_ty(sp, nid); + (ty::TypeScheme { generics: ty::Generics::empty(), ty: typ }, + ty::GenericPredicates::empty()) + } + Def::Fn(id) | Def::Method(id) | + Def::Static(id, _) | Def::Variant(_, id) | + Def::Struct(id) | Def::Const(id) | Def::AssociatedConst(id) => { + (self.tcx.lookup_item_type(id), self.tcx.lookup_predicates(id)) + } + Def::Trait(_) | + Def::Enum(..) | + Def::TyAlias(..) | + Def::AssociatedTy(..) | + Def::PrimTy(_) | + Def::TyParam(..) | + Def::Mod(..) | + Def::ForeignMod(..) | + Def::Label(..) | + Def::SelfTy(..) | + Def::Err => { + span_bug!(sp, "expected value, found {:?}", defn); + } } } -} -// Instantiates the given path, which must refer to an item with the given -// number of type parameters and type. -pub fn instantiate_path(&self, - segments: &[hir::PathSegment], - type_scheme: TypeScheme<'tcx>, - type_predicates: &ty::GenericPredicates<'tcx>, - opt_self_ty: Option>, - def: Def, - span: Span, - node_id: ast::NodeId) { - debug!("instantiate_path(path={:?}, def={:?}, node_id={}, type_scheme={:?})", - segments, - def, - node_id, - type_scheme); + // Instantiates the given path, which must refer to an item with the given + // number of type parameters and type. + pub fn instantiate_path(&self, + segments: &[hir::PathSegment], + type_scheme: TypeScheme<'tcx>, + type_predicates: &ty::GenericPredicates<'tcx>, + opt_self_ty: Option>, + def: Def, + span: Span, + node_id: ast::NodeId) { + debug!("instantiate_path(path={:?}, def={:?}, node_id={}, type_scheme={:?})", + segments, + def, + node_id, + type_scheme); - // We need to extract the type parameters supplied by the user in - // the path `path`. Due to the current setup, this is a bit of a - // tricky-process; the problem is that resolve only tells us the - // end-point of the path resolution, and not the intermediate steps. - // Luckily, we can (at least for now) deduce the intermediate steps - // just from the end-point. - // - // There are basically four cases to consider: - // - // 1. Reference to a *type*, such as a struct or enum: - // - // mod a { struct Foo { ... } } - // - // Because we don't allow types to be declared within one - // another, a path that leads to a type will always look like - // `a::b::Foo` where `a` and `b` are modules. This implies - // that only the final segment can have type parameters, and - // they are located in the TypeSpace. - // - // *Note:* Generally speaking, references to types don't - // actually pass through this function, but rather the - // `ast_ty_to_ty` function in `astconv`. However, in the case - // of struct patterns (and maybe literals) we do invoke - // `instantiate_path` to get the general type of an instance of - // a struct. (In these cases, there are actually no type - // parameters permitted at present, but perhaps we will allow - // them in the future.) - // - // 1b. Reference to an enum variant or tuple-like struct: - // - // struct foo(...) - // enum E { foo(...) } - // - // In these cases, the parameters are declared in the type - // space. - // - // 2. Reference to a *fn item*: - // - // fn foo() { } - // - // In this case, the path will again always have the form - // `a::b::foo::` where only the final segment should have - // type parameters. However, in this case, those parameters are - // declared on a value, and hence are in the `FnSpace`. - // - // 3. Reference to a *method*: - // - // impl SomeStruct { - // fn foo(...) - // } - // - // Here we can have a path like - // `a::b::SomeStruct::::foo::`, in which case parameters - // may appear in two places. The penultimate segment, - // `SomeStruct::`, contains parameters in TypeSpace, and the - // final segment, `foo::` contains parameters in fn space. - // - // 4. Reference to an *associated const*: - // - // impl AnotherStruct { - // const FOO: B = BAR; - // } - // - // The path in this case will look like - // `a::b::AnotherStruct::::FOO`, so the penultimate segment - // only will have parameters in TypeSpace. - // - // The first step then is to categorize the segments appropriately. + // We need to extract the type parameters supplied by the user in + // the path `path`. Due to the current setup, this is a bit of a + // tricky-process; the problem is that resolve only tells us the + // end-point of the path resolution, and not the intermediate steps. + // Luckily, we can (at least for now) deduce the intermediate steps + // just from the end-point. + // + // There are basically four cases to consider: + // + // 1. Reference to a *type*, such as a struct or enum: + // + // mod a { struct Foo { ... } } + // + // Because we don't allow types to be declared within one + // another, a path that leads to a type will always look like + // `a::b::Foo` where `a` and `b` are modules. This implies + // that only the final segment can have type parameters, and + // they are located in the TypeSpace. + // + // *Note:* Generally speaking, references to types don't + // actually pass through this function, but rather the + // `ast_ty_to_ty` function in `astconv`. However, in the case + // of struct patterns (and maybe literals) we do invoke + // `instantiate_path` to get the general type of an instance of + // a struct. (In these cases, there are actually no type + // parameters permitted at present, but perhaps we will allow + // them in the future.) + // + // 1b. Reference to an enum variant or tuple-like struct: + // + // struct foo(...) + // enum E { foo(...) } + // + // In these cases, the parameters are declared in the type + // space. + // + // 2. Reference to a *fn item*: + // + // fn foo() { } + // + // In this case, the path will again always have the form + // `a::b::foo::` where only the final segment should have + // type parameters. However, in this case, those parameters are + // declared on a value, and hence are in the `FnSpace`. + // + // 3. Reference to a *method*: + // + // impl SomeStruct { + // fn foo(...) + // } + // + // Here we can have a path like + // `a::b::SomeStruct::::foo::`, in which case parameters + // may appear in two places. The penultimate segment, + // `SomeStruct::`, contains parameters in TypeSpace, and the + // final segment, `foo::` contains parameters in fn space. + // + // 4. Reference to an *associated const*: + // + // impl AnotherStruct { + // const FOO: B = BAR; + // } + // + // The path in this case will look like + // `a::b::AnotherStruct::::FOO`, so the penultimate segment + // only will have parameters in TypeSpace. + // + // The first step then is to categorize the segments appropriately. - assert!(!segments.is_empty()); + assert!(!segments.is_empty()); - let mut ufcs_associated = None; - let mut segment_spaces: Vec<_>; - match def { - // Case 1 and 1b. Reference to a *type* or *enum variant*. - Def::SelfTy(..) | - Def::Struct(..) | - Def::Variant(..) | - Def::Enum(..) | - Def::TyAlias(..) | - Def::AssociatedTy(..) | - Def::Trait(..) | - Def::PrimTy(..) | - Def::TyParam(..) => { - // Everything but the final segment should have no - // parameters at all. - segment_spaces = vec![None; segments.len() - 1]; - segment_spaces.push(Some(subst::TypeSpace)); - } - - // Case 2. Reference to a top-level value. - Def::Fn(..) | - Def::Const(..) | - Def::Static(..) => { - segment_spaces = vec![None; segments.len() - 1]; - segment_spaces.push(Some(subst::FnSpace)); - } - - // Case 3. Reference to a method. - Def::Method(def_id) => { - let container = self.tcx.impl_or_trait_item(def_id).container(); - match container { - ty::TraitContainer(trait_did) => { - callee::check_legal_trait_for_method_call(self.ccx, span, trait_did) - } - ty::ImplContainer(_) => {} + let mut ufcs_associated = None; + let mut segment_spaces: Vec<_>; + match def { + // Case 1 and 1b. Reference to a *type* or *enum variant*. + Def::SelfTy(..) | + Def::Struct(..) | + Def::Variant(..) | + Def::Enum(..) | + Def::TyAlias(..) | + Def::AssociatedTy(..) | + Def::Trait(..) | + Def::PrimTy(..) | + Def::TyParam(..) => { + // Everything but the final segment should have no + // parameters at all. + segment_spaces = vec![None; segments.len() - 1]; + segment_spaces.push(Some(subst::TypeSpace)); } - if segments.len() >= 2 { - segment_spaces = vec![None; segments.len() - 2]; - segment_spaces.push(Some(subst::TypeSpace)); + // Case 2. Reference to a top-level value. + Def::Fn(..) | + Def::Const(..) | + Def::Static(..) => { + segment_spaces = vec![None; segments.len() - 1]; segment_spaces.push(Some(subst::FnSpace)); - } else { - // `::method` will end up here, and so can `T::method`. - let self_ty = opt_self_ty.expect("UFCS sugared method missing Self"); - segment_spaces = vec![Some(subst::FnSpace)]; - ufcs_associated = Some((container, self_ty)); } - } - Def::AssociatedConst(def_id) => { - let container = self.tcx.impl_or_trait_item(def_id).container(); - match container { - ty::TraitContainer(trait_did) => { - callee::check_legal_trait_for_method_call(self.ccx, span, trait_did) + // Case 3. Reference to a method. + Def::Method(def_id) => { + let container = self.tcx.impl_or_trait_item(def_id).container(); + match container { + ty::TraitContainer(trait_did) => { + callee::check_legal_trait_for_method_call(self.ccx, span, trait_did) + } + ty::ImplContainer(_) => {} + } + + if segments.len() >= 2 { + segment_spaces = vec![None; segments.len() - 2]; + segment_spaces.push(Some(subst::TypeSpace)); + segment_spaces.push(Some(subst::FnSpace)); + } else { + // `::method` will end up here, and so can `T::method`. + let self_ty = opt_self_ty.expect("UFCS sugared method missing Self"); + segment_spaces = vec![Some(subst::FnSpace)]; + ufcs_associated = Some((container, self_ty)); } - ty::ImplContainer(_) => {} } - if segments.len() >= 2 { - segment_spaces = vec![None; segments.len() - 2]; - segment_spaces.push(Some(subst::TypeSpace)); - segment_spaces.push(None); + Def::AssociatedConst(def_id) => { + let container = self.tcx.impl_or_trait_item(def_id).container(); + match container { + ty::TraitContainer(trait_did) => { + callee::check_legal_trait_for_method_call(self.ccx, span, trait_did) + } + ty::ImplContainer(_) => {} + } + + if segments.len() >= 2 { + segment_spaces = vec![None; segments.len() - 2]; + segment_spaces.push(Some(subst::TypeSpace)); + segment_spaces.push(None); + } else { + // `::CONST` will end up here, and so can `T::CONST`. + let self_ty = opt_self_ty.expect("UFCS sugared const missing Self"); + segment_spaces = vec![None]; + ufcs_associated = Some((container, self_ty)); + } + } + + // Other cases. Various nonsense that really shouldn't show up + // here. If they do, an error will have been reported + // elsewhere. (I hope) + Def::Mod(..) | + Def::ForeignMod(..) | + Def::Local(..) | + Def::Label(..) | + Def::Upvar(..) => { + segment_spaces = vec![None; segments.len()]; + } + + Def::Err => { + self.set_tainted_by_errors(); + segment_spaces = vec![None; segments.len()]; + } + } + assert_eq!(segment_spaces.len(), segments.len()); + + // In `>::method`, `A` and `B` are mandatory, but + // `opt_self_ty` can also be Some for `Foo::method`, where Foo's + // type parameters are not mandatory. + let require_type_space = opt_self_ty.is_some() && ufcs_associated.is_none(); + + debug!("segment_spaces={:?}", segment_spaces); + + // Next, examine the definition, and determine how many type + // parameters we expect from each space. + let type_defs = &type_scheme.generics.types; + let region_defs = &type_scheme.generics.regions; + + // Now that we have categorized what space the parameters for each + // segment belong to, let's sort out the parameters that the user + // provided (if any) into their appropriate spaces. We'll also report + // errors if type parameters are provided in an inappropriate place. + let mut substs = Substs::empty(); + for (&opt_space, segment) in segment_spaces.iter().zip(segments) { + if let Some(space) = opt_space { + self.push_explicit_parameters_from_segment_to_substs(space, + span, + type_defs, + region_defs, + segment, + &mut substs); } else { - // `::CONST` will end up here, and so can `T::CONST`. - let self_ty = opt_self_ty.expect("UFCS sugared const missing Self"); - segment_spaces = vec![None]; - ufcs_associated = Some((container, self_ty)); + self.tcx.prohibit_type_params(slice::ref_slice(segment)); + } + } + if let Some(self_ty) = opt_self_ty { + if type_defs.len(subst::SelfSpace) == 1 { + substs.types.push(subst::SelfSpace, self_ty); } } - // Other cases. Various nonsense that really shouldn't show up - // here. If they do, an error will have been reported - // elsewhere. (I hope) - Def::Mod(..) | - Def::ForeignMod(..) | - Def::Local(..) | - Def::Label(..) | - Def::Upvar(..) => { - segment_spaces = vec![None; segments.len()]; + // Now we have to compare the types that the user *actually* + // provided against the types that were *expected*. If the user + // did not provide any types, then we want to substitute inference + // variables. If the user provided some types, we may still need + // to add defaults. If the user provided *too many* types, that's + // a problem. + for &space in &[subst::SelfSpace, subst::TypeSpace, subst::FnSpace] { + self.adjust_type_parameters(span, space, type_defs, + require_type_space, &mut substs); + assert_eq!(substs.types.len(space), type_defs.len(space)); + + self.adjust_region_parameters(span, space, region_defs, &mut substs); + assert_eq!(substs.regions.len(space), region_defs.len(space)); } - Def::Err => { - self.set_tainted_by_errors(); - segment_spaces = vec![None; segments.len()]; - } - } - assert_eq!(segment_spaces.len(), segments.len()); + // The things we are substituting into the type should not contain + // escaping late-bound regions, and nor should the base type scheme. + let substs = self.tcx.mk_substs(substs); + assert!(!substs.has_regions_escaping_depth(0)); + assert!(!type_scheme.has_escaping_regions()); - // In `>::method`, `A` and `B` are mandatory, but - // `opt_self_ty` can also be Some for `Foo::method`, where Foo's - // type parameters are not mandatory. - let require_type_space = opt_self_ty.is_some() && ufcs_associated.is_none(); + // Add all the obligations that are required, substituting and + // normalized appropriately. + let bounds = self.instantiate_bounds(span, &substs, &type_predicates); + self.add_obligations_for_parameters( + traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def.def_id())), + &bounds); - debug!("segment_spaces={:?}", segment_spaces); - - // Next, examine the definition, and determine how many type - // parameters we expect from each space. - let type_defs = &type_scheme.generics.types; - let region_defs = &type_scheme.generics.regions; - - // Now that we have categorized what space the parameters for each - // segment belong to, let's sort out the parameters that the user - // provided (if any) into their appropriate spaces. We'll also report - // errors if type parameters are provided in an inappropriate place. - let mut substs = Substs::empty(); - for (&opt_space, segment) in segment_spaces.iter().zip(segments) { - if let Some(space) = opt_space { - self.push_explicit_parameters_from_segment_to_substs(space, - span, - type_defs, - region_defs, - segment, - &mut substs); - } else { - self.tcx.prohibit_type_params(slice::ref_slice(segment)); - } - } - if let Some(self_ty) = opt_self_ty { - if type_defs.len(subst::SelfSpace) == 1 { - substs.types.push(subst::SelfSpace, self_ty); - } - } - - // Now we have to compare the types that the user *actually* - // provided against the types that were *expected*. If the user - // did not provide any types, then we want to substitute inference - // variables. If the user provided some types, we may still need - // to add defaults. If the user provided *too many* types, that's - // a problem. - for &space in &[subst::SelfSpace, subst::TypeSpace, subst::FnSpace] { - self.adjust_type_parameters(span, space, type_defs, - require_type_space, &mut substs); - assert_eq!(substs.types.len(space), type_defs.len(space)); - - self.adjust_region_parameters(span, space, region_defs, &mut substs); - assert_eq!(substs.regions.len(space), region_defs.len(space)); - } - - // The things we are substituting into the type should not contain - // escaping late-bound regions, and nor should the base type scheme. - let substs = self.tcx.mk_substs(substs); - assert!(!substs.has_regions_escaping_depth(0)); - assert!(!type_scheme.has_escaping_regions()); - - // Add all the obligations that are required, substituting and - // normalized appropriately. - let bounds = self.instantiate_bounds(span, &substs, &type_predicates); - self.add_obligations_for_parameters( - traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def.def_id())), - &bounds); - - // Substitute the values for the type parameters into the type of - // the referenced item. - let ty_substituted = self.instantiate_type_scheme(span, &substs, &type_scheme.ty); + // Substitute the values for the type parameters into the type of + // the referenced item. + let ty_substituted = self.instantiate_type_scheme(span, &substs, &type_scheme.ty); - if let Some((ty::ImplContainer(impl_def_id), self_ty)) = ufcs_associated { - // In the case of `Foo::method` and `>::method`, if `method` - // is inherent, there is no `Self` parameter, instead, the impl needs - // type parameters, which we can infer by unifying the provided `Self` - // with the substituted impl type. - let impl_scheme = self.tcx.lookup_item_type(impl_def_id); - assert_eq!(substs.types.len(subst::TypeSpace), - impl_scheme.generics.types.len(subst::TypeSpace)); - assert_eq!(substs.regions.len(subst::TypeSpace), - impl_scheme.generics.regions.len(subst::TypeSpace)); + if let Some((ty::ImplContainer(impl_def_id), self_ty)) = ufcs_associated { + // In the case of `Foo::method` and `>::method`, if `method` + // is inherent, there is no `Self` parameter, instead, the impl needs + // type parameters, which we can infer by unifying the provided `Self` + // with the substituted impl type. + let impl_scheme = self.tcx.lookup_item_type(impl_def_id); + assert_eq!(substs.types.len(subst::TypeSpace), + impl_scheme.generics.types.len(subst::TypeSpace)); + assert_eq!(substs.regions.len(subst::TypeSpace), + impl_scheme.generics.regions.len(subst::TypeSpace)); - let impl_ty = self.instantiate_type_scheme(span, &substs, &impl_scheme.ty); - match self.sub_types(false, TypeOrigin::Misc(span), self_ty, impl_ty) { - Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - } - Err(_) => { - span_bug!(span, - "instantiate_path: (UFCS) {:?} was a subtype of {:?} but now is not?", - self_ty, - impl_ty); + let impl_ty = self.instantiate_type_scheme(span, &substs, &impl_scheme.ty); + match self.sub_types(false, TypeOrigin::Misc(span), self_ty, impl_ty) { + Ok(InferOk { obligations, .. }) => { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()); + } + Err(_) => { + span_bug!(span, + "instantiate_path: (UFCS) {:?} was a subtype of {:?} but now is not?", + self_ty, + impl_ty); + } } } - } - debug!("instantiate_path: type of {:?} is {:?}", - node_id, - ty_substituted); - self.write_ty(node_id, ty_substituted); - self.write_substs(node_id, ty::ItemSubsts { - substs: substs - }); -} + debug!("instantiate_path: type of {:?} is {:?}", + node_id, + ty_substituted); + self.write_ty(node_id, ty_substituted); + self.write_substs(node_id, ty::ItemSubsts { + substs: substs + }); + } /// Finds the parameters that the user provided and adds them to `substs`. If too many /// parameters are provided, then reports an error and clears the output vector. @@ -4628,40 +4634,40 @@ pub fn instantiate_path(&self, self.region_vars_for_defs(span, desired)); } -fn structurally_resolve_type_or_else(&self, sp: Span, ty: Ty<'tcx>, f: F) - -> Ty<'tcx> - where F: Fn() -> Ty<'tcx> -{ - let mut ty = self.resolve_type_vars_with_obligations(ty); + fn structurally_resolve_type_or_else(&self, sp: Span, ty: Ty<'tcx>, f: F) + -> Ty<'tcx> + where F: Fn() -> Ty<'tcx> + { + let mut ty = self.resolve_type_vars_with_obligations(ty); - if ty.is_ty_var() { - let alternative = f(); + if ty.is_ty_var() { + let alternative = f(); - // If not, error. - if alternative.is_ty_var() || alternative.references_error() { - if !self.is_tainted_by_errors() { - self.type_error_message(sp, |_actual| { - "the type of this value must be known in this context".to_string() - }, ty, None); + // If not, error. + if alternative.is_ty_var() || alternative.references_error() { + if !self.is_tainted_by_errors() { + self.type_error_message(sp, |_actual| { + "the type of this value must be known in this context".to_string() + }, ty, None); + } + self.demand_suptype(sp, self.tcx.types.err, ty); + ty = self.tcx.types.err; + } else { + self.demand_suptype(sp, alternative, ty); + ty = alternative; } - self.demand_suptype(sp, self.tcx.types.err, ty); - ty = self.tcx.types.err; - } else { - self.demand_suptype(sp, alternative, ty); - ty = alternative; } + + ty } - ty -} - -// Resolves `typ` by a single level if `typ` is a type variable. If no -// resolution is possible, then an error is reported. -pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - self.structurally_resolve_type_or_else(sp, ty, || { - self.tcx.types.err - }) -} + // Resolves `typ` by a single level if `typ` is a type variable. If no + // resolution is possible, then an error is reported. + pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { + self.structurally_resolve_type_or_else(sp, ty, || { + self.tcx.types.err + }) + } } // Returns true if b contains a break that can exit from b diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 3986b866033..8604dadf46d 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -18,330 +18,335 @@ use syntax::parse::token; use rustc::hir; impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { -/// Check a `a = b` -pub fn check_binop_assign(&self, - expr: &'gcx hir::Expr, - op: hir::BinOp, - lhs_expr: &'gcx hir::Expr, - rhs_expr: &'gcx hir::Expr) -{ - self.check_expr_with_lvalue_pref(lhs_expr, PreferMutLvalue); + /// Check a `a = b` + pub fn check_binop_assign(&self, + expr: &'gcx hir::Expr, + op: hir::BinOp, + lhs_expr: &'gcx hir::Expr, + rhs_expr: &'gcx hir::Expr) + { + self.check_expr_with_lvalue_pref(lhs_expr, PreferMutLvalue); - let lhs_ty = self.resolve_type_vars_with_obligations(self.expr_ty(lhs_expr)); - let (rhs_ty, return_ty) = - self.check_overloaded_binop(expr, lhs_expr, lhs_ty, rhs_expr, op, IsAssign::Yes); - let rhs_ty = self.resolve_type_vars_with_obligations(rhs_ty); - - if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) { - self.enforce_builtin_binop_types(lhs_expr, lhs_ty, rhs_expr, rhs_ty, op); - self.write_nil(expr.id); - } else { - self.write_ty(expr.id, return_ty); - } - - let tcx = self.tcx; - if !tcx.expr_is_lval(lhs_expr) { - span_err!(tcx.sess, lhs_expr.span, E0067, "invalid left-hand side expression"); - } -} - -/// Check a potentially overloaded binary operator. -pub fn check_binop(&self, - expr: &'gcx hir::Expr, - op: hir::BinOp, - lhs_expr: &'gcx hir::Expr, - rhs_expr: &'gcx hir::Expr) -{ - let tcx = self.tcx; - - debug!("check_binop(expr.id={}, expr={:?}, op={:?}, lhs_expr={:?}, rhs_expr={:?})", - expr.id, - expr, - op, - lhs_expr, - rhs_expr); - - self.check_expr(lhs_expr); - let lhs_ty = self.resolve_type_vars_with_obligations(self.expr_ty(lhs_expr)); - - match BinOpCategory::from(op) { - BinOpCategory::Shortcircuit => { - // && and || are a simple case. - self.demand_suptype(lhs_expr.span, tcx.mk_bool(), lhs_ty); - self.check_expr_coercable_to_type(rhs_expr, tcx.mk_bool()); - self.write_ty(expr.id, tcx.mk_bool()); - } - _ => { - // Otherwise, we always treat operators as if they are - // overloaded. This is the way to be most flexible w/r/t - // types that get inferred. - let (rhs_ty, return_ty) = - self.check_overloaded_binop(expr, lhs_expr, lhs_ty, rhs_expr, op, IsAssign::No); - - // Supply type inference hints if relevant. Probably these - // hints should be enforced during select as part of the - // `consider_unification_despite_ambiguity` routine, but this - // more convenient for now. - // - // The basic idea is to help type inference by taking - // advantage of things we know about how the impls for - // scalar types are arranged. This is important in a - // scenario like `1_u32 << 2`, because it lets us quickly - // deduce that the result type should be `u32`, even - // though we don't know yet what type 2 has and hence - // can't pin this down to a specific impl. - let rhs_ty = self.resolve_type_vars_with_obligations(rhs_ty); - if - !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && - is_builtin_binop(lhs_ty, rhs_ty, op) - { - let builtin_return_ty = - self.enforce_builtin_binop_types(lhs_expr, lhs_ty, rhs_expr, rhs_ty, op); - self.demand_suptype(expr.span, builtin_return_ty, return_ty); - } + let lhs_ty = self.resolve_type_vars_with_obligations(self.expr_ty(lhs_expr)); + let (rhs_ty, return_ty) = + self.check_overloaded_binop(expr, lhs_expr, lhs_ty, rhs_expr, op, IsAssign::Yes); + let rhs_ty = self.resolve_type_vars_with_obligations(rhs_ty); + if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) { + self.enforce_builtin_binop_types(lhs_expr, lhs_ty, rhs_expr, rhs_ty, op); + self.write_nil(expr.id); + } else { self.write_ty(expr.id, return_ty); } - } -} -fn enforce_builtin_binop_types(&self, - lhs_expr: &'gcx hir::Expr, - lhs_ty: Ty<'tcx>, - rhs_expr: &'gcx hir::Expr, - rhs_ty: Ty<'tcx>, - op: hir::BinOp) - -> Ty<'tcx> -{ - debug_assert!(is_builtin_binop(lhs_ty, rhs_ty, op)); - - let tcx = self.tcx; - match BinOpCategory::from(op) { - BinOpCategory::Shortcircuit => { - self.demand_suptype(lhs_expr.span, tcx.mk_bool(), lhs_ty); - self.demand_suptype(rhs_expr.span, tcx.mk_bool(), rhs_ty); - tcx.mk_bool() - } - - BinOpCategory::Shift => { - // result type is same as LHS always - lhs_ty - } - - BinOpCategory::Math | - BinOpCategory::Bitwise => { - // both LHS and RHS and result will have the same type - self.demand_suptype(rhs_expr.span, lhs_ty, rhs_ty); - lhs_ty - } - - BinOpCategory::Comparison => { - // both LHS and RHS and result will have the same type - self.demand_suptype(rhs_expr.span, lhs_ty, rhs_ty); - tcx.mk_bool() + let tcx = self.tcx; + if !tcx.expr_is_lval(lhs_expr) { + span_err!(tcx.sess, lhs_expr.span, E0067, "invalid left-hand side expression"); } } -} -fn check_overloaded_binop(&self, - expr: &'gcx hir::Expr, - lhs_expr: &'gcx hir::Expr, - lhs_ty: Ty<'tcx>, - rhs_expr: &'gcx hir::Expr, - op: hir::BinOp, - is_assign: IsAssign) - -> (Ty<'tcx>, Ty<'tcx>) -{ - debug!("check_overloaded_binop(expr.id={}, lhs_ty={:?}, is_assign={:?})", - expr.id, - lhs_ty, - is_assign); + /// Check a potentially overloaded binary operator. + pub fn check_binop(&self, + expr: &'gcx hir::Expr, + op: hir::BinOp, + lhs_expr: &'gcx hir::Expr, + rhs_expr: &'gcx hir::Expr) + { + let tcx = self.tcx; - let (name, trait_def_id) = self.name_and_trait_def_id(op, is_assign); + debug!("check_binop(expr.id={}, expr={:?}, op={:?}, lhs_expr={:?}, rhs_expr={:?})", + expr.id, + expr, + op, + lhs_expr, + rhs_expr); - // NB: As we have not yet type-checked the RHS, we don't have the - // type at hand. Make a variable to represent it. The whole reason - // for this indirection is so that, below, we can check the expr - // using this variable as the expected type, which sometimes lets - // us do better coercions than we would be able to do otherwise, - // particularly for things like `String + &String`. - let rhs_ty_var = self.next_ty_var(); + self.check_expr(lhs_expr); + let lhs_ty = self.resolve_type_vars_with_obligations(self.expr_ty(lhs_expr)); - let return_ty = match self.lookup_op_method(expr, lhs_ty, vec![rhs_ty_var], - token::intern(name), trait_def_id, - lhs_expr) { - Ok(return_ty) => return_ty, - Err(()) => { - // error types are considered "builtin" - if !lhs_ty.references_error() { - if let IsAssign::Yes = is_assign { - span_err!(self.tcx.sess, lhs_expr.span, E0368, - "binary assignment operation `{}=` cannot be applied to type `{}`", - op.node.as_str(), - lhs_ty); - } else { - let mut err = struct_span_err!(self.tcx.sess, lhs_expr.span, E0369, - "binary operation `{}` cannot be applied to type `{}`", - op.node.as_str(), - lhs_ty); - let missing_trait = match op.node { - hir::BiAdd => Some("std::ops::Add"), - hir::BiSub => Some("std::ops::Sub"), - hir::BiMul => Some("std::ops::Mul"), - hir::BiDiv => Some("std::ops::Div"), - hir::BiRem => Some("std::ops::Rem"), - hir::BiBitAnd => Some("std::ops::BitAnd"), - hir::BiBitOr => Some("std::ops::BitOr"), - hir::BiShl => Some("std::ops::Shl"), - hir::BiShr => Some("std::ops::Shr"), - hir::BiEq | hir::BiNe => Some("std::cmp::PartialEq"), - hir::BiLt | hir::BiLe | hir::BiGt | hir::BiGe => - Some("std::cmp::PartialOrd"), - _ => None - }; + match BinOpCategory::from(op) { + BinOpCategory::Shortcircuit => { + // && and || are a simple case. + self.demand_suptype(lhs_expr.span, tcx.mk_bool(), lhs_ty); + self.check_expr_coercable_to_type(rhs_expr, tcx.mk_bool()); + self.write_ty(expr.id, tcx.mk_bool()); + } + _ => { + // Otherwise, we always treat operators as if they are + // overloaded. This is the way to be most flexible w/r/t + // types that get inferred. + let (rhs_ty, return_ty) = + self.check_overloaded_binop(expr, lhs_expr, lhs_ty, + rhs_expr, op, IsAssign::No); - if let Some(missing_trait) = missing_trait { - span_note!(&mut err, lhs_expr.span, - "an implementation of `{}` might be missing for `{}`", - missing_trait, lhs_ty); + // Supply type inference hints if relevant. Probably these + // hints should be enforced during select as part of the + // `consider_unification_despite_ambiguity` routine, but this + // more convenient for now. + // + // The basic idea is to help type inference by taking + // advantage of things we know about how the impls for + // scalar types are arranged. This is important in a + // scenario like `1_u32 << 2`, because it lets us quickly + // deduce that the result type should be `u32`, even + // though we don't know yet what type 2 has and hence + // can't pin this down to a specific impl. + let rhs_ty = self.resolve_type_vars_with_obligations(rhs_ty); + if + !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && + is_builtin_binop(lhs_ty, rhs_ty, op) + { + let builtin_return_ty = + self.enforce_builtin_binop_types(lhs_expr, lhs_ty, rhs_expr, rhs_ty, op); + self.demand_suptype(expr.span, builtin_return_ty, return_ty); + } + + self.write_ty(expr.id, return_ty); + } + } + } + + fn enforce_builtin_binop_types(&self, + lhs_expr: &'gcx hir::Expr, + lhs_ty: Ty<'tcx>, + rhs_expr: &'gcx hir::Expr, + rhs_ty: Ty<'tcx>, + op: hir::BinOp) + -> Ty<'tcx> + { + debug_assert!(is_builtin_binop(lhs_ty, rhs_ty, op)); + + let tcx = self.tcx; + match BinOpCategory::from(op) { + BinOpCategory::Shortcircuit => { + self.demand_suptype(lhs_expr.span, tcx.mk_bool(), lhs_ty); + self.demand_suptype(rhs_expr.span, tcx.mk_bool(), rhs_ty); + tcx.mk_bool() + } + + BinOpCategory::Shift => { + // result type is same as LHS always + lhs_ty + } + + BinOpCategory::Math | + BinOpCategory::Bitwise => { + // both LHS and RHS and result will have the same type + self.demand_suptype(rhs_expr.span, lhs_ty, rhs_ty); + lhs_ty + } + + BinOpCategory::Comparison => { + // both LHS and RHS and result will have the same type + self.demand_suptype(rhs_expr.span, lhs_ty, rhs_ty); + tcx.mk_bool() + } + } + } + + fn check_overloaded_binop(&self, + expr: &'gcx hir::Expr, + lhs_expr: &'gcx hir::Expr, + lhs_ty: Ty<'tcx>, + rhs_expr: &'gcx hir::Expr, + op: hir::BinOp, + is_assign: IsAssign) + -> (Ty<'tcx>, Ty<'tcx>) + { + debug!("check_overloaded_binop(expr.id={}, lhs_ty={:?}, is_assign={:?})", + expr.id, + lhs_ty, + is_assign); + + let (name, trait_def_id) = self.name_and_trait_def_id(op, is_assign); + + // NB: As we have not yet type-checked the RHS, we don't have the + // type at hand. Make a variable to represent it. The whole reason + // for this indirection is so that, below, we can check the expr + // using this variable as the expected type, which sometimes lets + // us do better coercions than we would be able to do otherwise, + // particularly for things like `String + &String`. + let rhs_ty_var = self.next_ty_var(); + + let return_ty = match self.lookup_op_method(expr, lhs_ty, vec![rhs_ty_var], + token::intern(name), trait_def_id, + lhs_expr) { + Ok(return_ty) => return_ty, + Err(()) => { + // error types are considered "builtin" + if !lhs_ty.references_error() { + if let IsAssign::Yes = is_assign { + span_err!(self.tcx.sess, lhs_expr.span, E0368, + "binary assignment operation `{}=` \ + cannot be applied to type `{}`", + op.node.as_str(), + lhs_ty); + } else { + let mut err = struct_span_err!(self.tcx.sess, lhs_expr.span, E0369, + "binary operation `{}` cannot be applied to type `{}`", + op.node.as_str(), + lhs_ty); + let missing_trait = match op.node { + hir::BiAdd => Some("std::ops::Add"), + hir::BiSub => Some("std::ops::Sub"), + hir::BiMul => Some("std::ops::Mul"), + hir::BiDiv => Some("std::ops::Div"), + hir::BiRem => Some("std::ops::Rem"), + hir::BiBitAnd => Some("std::ops::BitAnd"), + hir::BiBitOr => Some("std::ops::BitOr"), + hir::BiShl => Some("std::ops::Shl"), + hir::BiShr => Some("std::ops::Shr"), + hir::BiEq | hir::BiNe => Some("std::cmp::PartialEq"), + hir::BiLt | hir::BiLe | hir::BiGt | hir::BiGe => + Some("std::cmp::PartialOrd"), + _ => None + }; + + if let Some(missing_trait) = missing_trait { + span_note!(&mut err, lhs_expr.span, + "an implementation of `{}` might be missing for `{}`", + missing_trait, lhs_ty); + } + err.emit(); } - err.emit(); + } + self.tcx.types.err + } + }; + + // see `NB` above + self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var); + + (rhs_ty_var, return_ty) + } + + pub fn check_user_unop(&self, + op_str: &str, + mname: &str, + trait_did: Option, + ex: &'gcx hir::Expr, + operand_expr: &'gcx hir::Expr, + operand_ty: Ty<'tcx>, + op: hir::UnOp) + -> Ty<'tcx> + { + assert!(op.is_by_value()); + match self.lookup_op_method(ex, operand_ty, vec![], + token::intern(mname), trait_did, + operand_expr) { + Ok(t) => t, + Err(()) => { + self.type_error_message(ex.span, |actual| { + format!("cannot apply unary operator `{}` to type `{}`", + op_str, actual) + }, operand_ty, None); + self.tcx.types.err + } + } + } + + fn name_and_trait_def_id(&self, + op: hir::BinOp, + is_assign: IsAssign) + -> (&'static str, Option) { + let lang = &self.tcx.lang_items; + + if let IsAssign::Yes = is_assign { + match op.node { + hir::BiAdd => ("add_assign", lang.add_assign_trait()), + hir::BiSub => ("sub_assign", lang.sub_assign_trait()), + hir::BiMul => ("mul_assign", lang.mul_assign_trait()), + hir::BiDiv => ("div_assign", lang.div_assign_trait()), + hir::BiRem => ("rem_assign", lang.rem_assign_trait()), + hir::BiBitXor => ("bitxor_assign", lang.bitxor_assign_trait()), + hir::BiBitAnd => ("bitand_assign", lang.bitand_assign_trait()), + hir::BiBitOr => ("bitor_assign", lang.bitor_assign_trait()), + hir::BiShl => ("shl_assign", lang.shl_assign_trait()), + hir::BiShr => ("shr_assign", lang.shr_assign_trait()), + hir::BiLt | hir::BiLe | + hir::BiGe | hir::BiGt | + hir::BiEq | hir::BiNe | + hir::BiAnd | hir::BiOr => { + span_bug!(op.span, + "impossible assignment operation: {}=", + op.node.as_str()) } } - self.tcx.types.err - } - }; - - // see `NB` above - self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var); - - (rhs_ty_var, return_ty) -} - -pub fn check_user_unop(&self, - op_str: &str, - mname: &str, - trait_did: Option, - ex: &'gcx hir::Expr, - operand_expr: &'gcx hir::Expr, - operand_ty: Ty<'tcx>, - op: hir::UnOp) - -> Ty<'tcx> -{ - assert!(op.is_by_value()); - match self.lookup_op_method(ex, operand_ty, vec![], - token::intern(mname), trait_did, - operand_expr) { - Ok(t) => t, - Err(()) => { - self.type_error_message(ex.span, |actual| { - format!("cannot apply unary operator `{}` to type `{}`", - op_str, actual) - }, operand_ty, None); - self.tcx.types.err - } - } -} - -fn name_and_trait_def_id(&self, - op: hir::BinOp, - is_assign: IsAssign) - -> (&'static str, Option) { - let lang = &self.tcx.lang_items; - - if let IsAssign::Yes = is_assign { - match op.node { - hir::BiAdd => ("add_assign", lang.add_assign_trait()), - hir::BiSub => ("sub_assign", lang.sub_assign_trait()), - hir::BiMul => ("mul_assign", lang.mul_assign_trait()), - hir::BiDiv => ("div_assign", lang.div_assign_trait()), - hir::BiRem => ("rem_assign", lang.rem_assign_trait()), - hir::BiBitXor => ("bitxor_assign", lang.bitxor_assign_trait()), - hir::BiBitAnd => ("bitand_assign", lang.bitand_assign_trait()), - hir::BiBitOr => ("bitor_assign", lang.bitor_assign_trait()), - hir::BiShl => ("shl_assign", lang.shl_assign_trait()), - hir::BiShr => ("shr_assign", lang.shr_assign_trait()), - hir::BiLt | hir::BiLe | hir::BiGe | hir::BiGt | hir::BiEq | hir::BiNe | hir::BiAnd | - hir::BiOr => { - span_bug!(op.span, - "impossible assignment operation: {}=", - op.node.as_str()) - } - } - } else { - match op.node { - hir::BiAdd => ("add", lang.add_trait()), - hir::BiSub => ("sub", lang.sub_trait()), - hir::BiMul => ("mul", lang.mul_trait()), - hir::BiDiv => ("div", lang.div_trait()), - hir::BiRem => ("rem", lang.rem_trait()), - hir::BiBitXor => ("bitxor", lang.bitxor_trait()), - hir::BiBitAnd => ("bitand", lang.bitand_trait()), - hir::BiBitOr => ("bitor", lang.bitor_trait()), - hir::BiShl => ("shl", lang.shl_trait()), - hir::BiShr => ("shr", lang.shr_trait()), - hir::BiLt => ("lt", lang.ord_trait()), - hir::BiLe => ("le", lang.ord_trait()), - hir::BiGe => ("ge", lang.ord_trait()), - hir::BiGt => ("gt", lang.ord_trait()), - hir::BiEq => ("eq", lang.eq_trait()), - hir::BiNe => ("ne", lang.eq_trait()), - hir::BiAnd | hir::BiOr => { - span_bug!(op.span, "&& and || are not overloadable") + } else { + match op.node { + hir::BiAdd => ("add", lang.add_trait()), + hir::BiSub => ("sub", lang.sub_trait()), + hir::BiMul => ("mul", lang.mul_trait()), + hir::BiDiv => ("div", lang.div_trait()), + hir::BiRem => ("rem", lang.rem_trait()), + hir::BiBitXor => ("bitxor", lang.bitxor_trait()), + hir::BiBitAnd => ("bitand", lang.bitand_trait()), + hir::BiBitOr => ("bitor", lang.bitor_trait()), + hir::BiShl => ("shl", lang.shl_trait()), + hir::BiShr => ("shr", lang.shr_trait()), + hir::BiLt => ("lt", lang.ord_trait()), + hir::BiLe => ("le", lang.ord_trait()), + hir::BiGe => ("ge", lang.ord_trait()), + hir::BiGt => ("gt", lang.ord_trait()), + hir::BiEq => ("eq", lang.eq_trait()), + hir::BiNe => ("ne", lang.eq_trait()), + hir::BiAnd | hir::BiOr => { + span_bug!(op.span, "&& and || are not overloadable") + } } } } -} -fn lookup_op_method(&self, - expr: &'gcx hir::Expr, - lhs_ty: Ty<'tcx>, - other_tys: Vec>, - opname: ast::Name, - trait_did: Option, - lhs_expr: &'a hir::Expr) - -> Result,()> -{ - debug!("lookup_op_method(expr={:?}, lhs_ty={:?}, opname={:?}, trait_did={:?}, lhs_expr={:?})", - expr, - lhs_ty, - opname, - trait_did, - lhs_expr); + fn lookup_op_method(&self, + expr: &'gcx hir::Expr, + lhs_ty: Ty<'tcx>, + other_tys: Vec>, + opname: ast::Name, + trait_did: Option, + lhs_expr: &'a hir::Expr) + -> Result,()> + { + debug!("lookup_op_method(expr={:?}, lhs_ty={:?}, opname={:?}, \ + trait_did={:?}, lhs_expr={:?})", + expr, + lhs_ty, + opname, + trait_did, + lhs_expr); - let method = match trait_did { - Some(trait_did) => { - self.lookup_method_in_trait_adjusted(expr.span, - Some(lhs_expr), - opname, - trait_did, - 0, - false, - lhs_ty, - Some(other_tys)) - } - None => None - }; + let method = match trait_did { + Some(trait_did) => { + self.lookup_method_in_trait_adjusted(expr.span, + Some(lhs_expr), + opname, + trait_did, + 0, + false, + lhs_ty, + Some(other_tys)) + } + None => None + }; - match method { - Some(method) => { - let method_ty = method.ty; + match method { + Some(method) => { + let method_ty = method.ty; - // HACK(eddyb) Fully qualified path to work around a resolve bug. - let method_call = ::rustc::ty::MethodCall::expr(expr.id); - self.tables.borrow_mut().method_map.insert(method_call, method); + // HACK(eddyb) Fully qualified path to work around a resolve bug. + let method_call = ::rustc::ty::MethodCall::expr(expr.id); + self.tables.borrow_mut().method_map.insert(method_call, method); - // extract return type for method; all late bound regions - // should have been instantiated by now - let ret_ty = method_ty.fn_ret(); - Ok(self.tcx.no_late_bound_regions(&ret_ty).unwrap().unwrap()) - } - None => { - Err(()) + // extract return type for method; all late bound regions + // should have been instantiated by now + let ret_ty = method_ty.fn_ret(); + Ok(self.tcx.no_late_bound_regions(&ret_ty).unwrap().unwrap()) + } + None => { + Err(()) + } } } } -} // Binary operator categories. These categories summarize the behavior // with respect to the builtin operationrs supported. diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 931f77951eb..7b79f2ec9bf 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -114,54 +114,54 @@ macro_rules! ignore_err { // PUBLIC ENTRY POINTS impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { -pub fn regionck_expr(&self, e: &hir::Expr) { - let mut rcx = RegionCtxt::new(self, RepeatingScope(e.id), e.id, Subject(e.id)); - if self.err_count_since_creation() == 0 { - // regionck assumes typeck succeeded - rcx.visit_expr(e); - rcx.visit_region_obligations(e.id); - } - rcx.resolve_regions_and_report_errors(); -} - -/// Region checking during the WF phase for items. `wf_tys` are the -/// types from which we should derive implied bounds, if any. -pub fn regionck_item(&self, - item_id: ast::NodeId, - span: Span, - wf_tys: &[Ty<'tcx>]) { - debug!("regionck_item(item.id={:?}, wf_tys={:?}", item_id, wf_tys); - let mut rcx = RegionCtxt::new(self, RepeatingScope(item_id), item_id, Subject(item_id)); - rcx.free_region_map.relate_free_regions_from_predicates( - &self.parameter_environment.caller_bounds); - rcx.relate_free_regions(wf_tys, item_id, span); - rcx.visit_region_obligations(item_id); - rcx.resolve_regions_and_report_errors(); -} - -pub fn regionck_fn(&self, - fn_id: ast::NodeId, - fn_span: Span, - decl: &hir::FnDecl, - blk: &hir::Block) { - debug!("regionck_fn(id={})", fn_id); - let mut rcx = RegionCtxt::new(self, RepeatingScope(blk.id), blk.id, Subject(fn_id)); - - if self.err_count_since_creation() == 0 { - // regionck assumes typeck succeeded - rcx.visit_fn_body(fn_id, decl, blk, fn_span); + pub fn regionck_expr(&self, e: &hir::Expr) { + let mut rcx = RegionCtxt::new(self, RepeatingScope(e.id), e.id, Subject(e.id)); + if self.err_count_since_creation() == 0 { + // regionck assumes typeck succeeded + rcx.visit_expr(e); + rcx.visit_region_obligations(e.id); + } + rcx.resolve_regions_and_report_errors(); } - rcx.free_region_map.relate_free_regions_from_predicates( - &self.parameter_environment.caller_bounds); + /// Region checking during the WF phase for items. `wf_tys` are the + /// types from which we should derive implied bounds, if any. + pub fn regionck_item(&self, + item_id: ast::NodeId, + span: Span, + wf_tys: &[Ty<'tcx>]) { + debug!("regionck_item(item.id={:?}, wf_tys={:?}", item_id, wf_tys); + let mut rcx = RegionCtxt::new(self, RepeatingScope(item_id), item_id, Subject(item_id)); + rcx.free_region_map.relate_free_regions_from_predicates( + &self.parameter_environment.caller_bounds); + rcx.relate_free_regions(wf_tys, item_id, span); + rcx.visit_region_obligations(item_id); + rcx.resolve_regions_and_report_errors(); + } - rcx.resolve_regions_and_report_errors(); + pub fn regionck_fn(&self, + fn_id: ast::NodeId, + fn_span: Span, + decl: &hir::FnDecl, + blk: &hir::Block) { + debug!("regionck_fn(id={})", fn_id); + let mut rcx = RegionCtxt::new(self, RepeatingScope(blk.id), blk.id, Subject(fn_id)); - // For the top-level fn, store the free-region-map. We don't store - // any map for closures; they just share the same map as the - // function that created them. - self.tcx.store_free_region_map(fn_id, rcx.free_region_map); -} + if self.err_count_since_creation() == 0 { + // regionck assumes typeck succeeded + rcx.visit_fn_body(fn_id, decl, blk, fn_span); + } + + rcx.free_region_map.relate_free_regions_from_predicates( + &self.parameter_environment.caller_bounds); + + rcx.resolve_regions_and_report_errors(); + + // For the top-level fn, store the free-region-map. We don't store + // any map for closures; they just share the same map as the + // function that created them. + self.tcx.store_free_region_map(fn_id, rcx.free_region_map); + } } /////////////////////////////////////////////////////////////////////////// @@ -449,42 +449,42 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { subject_node_id); } -fn constrain_bindings_in_pat(&mut self, pat: &hir::Pat) { - let tcx = self.tcx; - debug!("regionck::visit_pat(pat={:?})", pat); - pat_util::pat_bindings(&tcx.def_map, pat, |_, id, span, _| { - // If we have a variable that contains region'd data, that - // data will be accessible from anywhere that the variable is - // accessed. We must be wary of loops like this: - // - // // from src/test/compile-fail/borrowck-lend-flow.rs - // let mut v = box 3, w = box 4; - // let mut x = &mut w; - // loop { - // **x += 1; // (2) - // borrow(v); //~ ERROR cannot borrow - // x = &mut v; // (1) - // } - // - // Typically, we try to determine the region of a borrow from - // those points where it is dereferenced. In this case, one - // might imagine that the lifetime of `x` need only be the - // body of the loop. But of course this is incorrect because - // the pointer that is created at point (1) is consumed at - // point (2), meaning that it must be live across the loop - // iteration. The easiest way to guarantee this is to require - // that the lifetime of any regions that appear in a - // variable's type enclose at least the variable's scope. + fn constrain_bindings_in_pat(&mut self, pat: &hir::Pat) { + let tcx = self.tcx; + debug!("regionck::visit_pat(pat={:?})", pat); + pat_util::pat_bindings(&tcx.def_map, pat, |_, id, span, _| { + // If we have a variable that contains region'd data, that + // data will be accessible from anywhere that the variable is + // accessed. We must be wary of loops like this: + // + // // from src/test/compile-fail/borrowck-lend-flow.rs + // let mut v = box 3, w = box 4; + // let mut x = &mut w; + // loop { + // **x += 1; // (2) + // borrow(v); //~ ERROR cannot borrow + // x = &mut v; // (1) + // } + // + // Typically, we try to determine the region of a borrow from + // those points where it is dereferenced. In this case, one + // might imagine that the lifetime of `x` need only be the + // body of the loop. But of course this is incorrect because + // the pointer that is created at point (1) is consumed at + // point (2), meaning that it must be live across the loop + // iteration. The easiest way to guarantee this is to require + // that the lifetime of any regions that appear in a + // variable's type enclose at least the variable's scope. - let var_scope = tcx.region_maps.var_scope(id); + let var_scope = tcx.region_maps.var_scope(id); - let origin = infer::BindingTypeIsNotValidAtDecl(span); - self.type_of_node_must_outlive(origin, id, ty::ReScope(var_scope)); + let origin = infer::BindingTypeIsNotValidAtDecl(span); + self.type_of_node_must_outlive(origin, id, ty::ReScope(var_scope)); - let typ = self.resolve_node_type(id); - dropck::check_safety_of_destructor_if_necessary(self, typ, span, var_scope); - }) -} + let typ = self.resolve_node_type(id); + dropck::check_safety_of_destructor_if_necessary(self, typ, span, var_scope); + }) + } } impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> { @@ -518,296 +518,296 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> { intravisit::walk_local(self, l); } -fn visit_expr(&mut self, expr: &hir::Expr) { - debug!("regionck::visit_expr(e={:?}, repeating_scope={})", - expr, self.repeating_scope); + fn visit_expr(&mut self, expr: &hir::Expr) { + debug!("regionck::visit_expr(e={:?}, repeating_scope={})", + expr, self.repeating_scope); - // No matter what, the type of each expression must outlive the - // scope of that expression. This also guarantees basic WF. - let expr_ty = self.resolve_node_type(expr.id); - // the region corresponding to this expression - let expr_region = ty::ReScope(self.tcx.region_maps.node_extent(expr.id)); - self.type_must_outlive(infer::ExprTypeIsNotInScope(expr_ty, expr.span), - expr_ty, expr_region); + // No matter what, the type of each expression must outlive the + // scope of that expression. This also guarantees basic WF. + let expr_ty = self.resolve_node_type(expr.id); + // the region corresponding to this expression + let expr_region = ty::ReScope(self.tcx.region_maps.node_extent(expr.id)); + self.type_must_outlive(infer::ExprTypeIsNotInScope(expr_ty, expr.span), + expr_ty, expr_region); - let method_call = MethodCall::expr(expr.id); - let opt_method_callee = self.tables.borrow().method_map.get(&method_call).cloned(); - let has_method_map = opt_method_callee.is_some(); + let method_call = MethodCall::expr(expr.id); + let opt_method_callee = self.tables.borrow().method_map.get(&method_call).cloned(); + let has_method_map = opt_method_callee.is_some(); - // If we are calling a method (either explicitly or via an - // overloaded operator), check that all of the types provided as - // arguments for its type parameters are well-formed, and all the regions - // provided as arguments outlive the call. - if let Some(callee) = opt_method_callee { - let origin = match expr.node { - hir::ExprMethodCall(..) => - infer::ParameterOrigin::MethodCall, - hir::ExprUnary(op, _) if op == hir::UnDeref => - infer::ParameterOrigin::OverloadedDeref, - _ => - infer::ParameterOrigin::OverloadedOperator - }; + // If we are calling a method (either explicitly or via an + // overloaded operator), check that all of the types provided as + // arguments for its type parameters are well-formed, and all the regions + // provided as arguments outlive the call. + if let Some(callee) = opt_method_callee { + let origin = match expr.node { + hir::ExprMethodCall(..) => + infer::ParameterOrigin::MethodCall, + hir::ExprUnary(op, _) if op == hir::UnDeref => + infer::ParameterOrigin::OverloadedDeref, + _ => + infer::ParameterOrigin::OverloadedOperator + }; - self.substs_wf_in_scope(origin, &callee.substs, expr.span, expr_region); - self.type_must_outlive(infer::ExprTypeIsNotInScope(callee.ty, expr.span), - callee.ty, expr_region); - } - - // Check any autoderefs or autorefs that appear. - let adjustment = self.tables.borrow().adjustments.get(&expr.id).map(|a| a.clone()); - if let Some(adjustment) = adjustment { - debug!("adjustment={:?}", adjustment); - match adjustment { - adjustment::AdjustDerefRef(adjustment::AutoDerefRef { - autoderefs, ref autoref, .. - }) => { - let expr_ty = self.resolve_node_type(expr.id); - self.constrain_autoderefs(expr, autoderefs, expr_ty); - if let Some(ref autoref) = *autoref { - self.link_autoref(expr, autoderefs, autoref); - - // Require that the resulting region encompasses - // the current node. - // - // FIXME(#6268) remove to support nested method calls - self.type_of_node_must_outlive(infer::AutoBorrow(expr.span), - expr.id, expr_region); - } - } - /* - adjustment::AutoObject(_, ref bounds, _, _) => { - // Determine if we are casting `expr` to a trait - // instance. If so, we have to be sure that the type - // of the source obeys the new region bound. - let source_ty = self.resolve_node_type(expr.id); - self.type_must_outlive(infer::RelateObjectBound(expr.span), - source_ty, bounds.region_bound); - } - */ - _ => {} + self.substs_wf_in_scope(origin, &callee.substs, expr.span, expr_region); + self.type_must_outlive(infer::ExprTypeIsNotInScope(callee.ty, expr.span), + callee.ty, expr_region); } - // If necessary, constrain destructors in the unadjusted form of this - // expression. + // Check any autoderefs or autorefs that appear. + let adjustment = self.tables.borrow().adjustments.get(&expr.id).map(|a| a.clone()); + if let Some(adjustment) = adjustment { + debug!("adjustment={:?}", adjustment); + match adjustment { + adjustment::AdjustDerefRef(adjustment::AutoDerefRef { + autoderefs, ref autoref, .. + }) => { + let expr_ty = self.resolve_node_type(expr.id); + self.constrain_autoderefs(expr, autoderefs, expr_ty); + if let Some(ref autoref) = *autoref { + self.link_autoref(expr, autoderefs, autoref); + + // Require that the resulting region encompasses + // the current node. + // + // FIXME(#6268) remove to support nested method calls + self.type_of_node_must_outlive(infer::AutoBorrow(expr.span), + expr.id, expr_region); + } + } + /* + adjustment::AutoObject(_, ref bounds, _, _) => { + // Determine if we are casting `expr` to a trait + // instance. If so, we have to be sure that the type + // of the source obeys the new region bound. + let source_ty = self.resolve_node_type(expr.id); + self.type_must_outlive(infer::RelateObjectBound(expr.span), + source_ty, bounds.region_bound); + } + */ + _ => {} + } + + // If necessary, constrain destructors in the unadjusted form of this + // expression. + let cmt_result = { + let mc = mc::MemCategorizationContext::new(self); + mc.cat_expr_unadjusted(expr) + }; + match cmt_result { + Ok(head_cmt) => { + self.check_safety_of_rvalue_destructor_if_necessary(head_cmt, + expr.span); + } + Err(..) => { + self.tcx.sess.delay_span_bug(expr.span, "cat_expr_unadjusted Errd"); + } + } + } + + // If necessary, constrain destructors in this expression. This will be + // the adjusted form if there is an adjustment. let cmt_result = { let mc = mc::MemCategorizationContext::new(self); - mc.cat_expr_unadjusted(expr) + mc.cat_expr(expr) }; match cmt_result { Ok(head_cmt) => { - self.check_safety_of_rvalue_destructor_if_necessary(head_cmt, - expr.span); + self.check_safety_of_rvalue_destructor_if_necessary(head_cmt, expr.span); } Err(..) => { - self.tcx.sess.delay_span_bug(expr.span, "cat_expr_unadjusted Errd"); + self.tcx.sess.delay_span_bug(expr.span, "cat_expr Errd"); } } - } - // If necessary, constrain destructors in this expression. This will be - // the adjusted form if there is an adjustment. - let cmt_result = { - let mc = mc::MemCategorizationContext::new(self); - mc.cat_expr(expr) - }; - match cmt_result { - Ok(head_cmt) => { - self.check_safety_of_rvalue_destructor_if_necessary(head_cmt, expr.span); - } - Err(..) => { - self.tcx.sess.delay_span_bug(expr.span, "cat_expr Errd"); - } - } - - debug!("regionck::visit_expr(e={:?}, repeating_scope={}) - visiting subexprs", - expr, self.repeating_scope); - match expr.node { - hir::ExprPath(..) => { - self.fcx.opt_node_ty_substs(expr.id, |item_substs| { - let origin = infer::ParameterOrigin::Path; - self.substs_wf_in_scope(origin, &item_substs.substs, expr.span, expr_region); - }); - } - - hir::ExprCall(ref callee, ref args) => { - if has_method_map { - self.constrain_call(expr, Some(&callee), - args.iter().map(|e| &**e), false); - } else { - self.constrain_callee(callee.id, expr, &callee); - self.constrain_call(expr, None, - args.iter().map(|e| &**e), false); + debug!("regionck::visit_expr(e={:?}, repeating_scope={}) - visiting subexprs", + expr, self.repeating_scope); + match expr.node { + hir::ExprPath(..) => { + self.fcx.opt_node_ty_substs(expr.id, |item_substs| { + let origin = infer::ParameterOrigin::Path; + self.substs_wf_in_scope(origin, &item_substs.substs, expr.span, expr_region); + }); } - intravisit::walk_expr(self, expr); - } - - hir::ExprMethodCall(_, _, ref args) => { - self.constrain_call(expr, Some(&args[0]), - args[1..].iter().map(|e| &**e), false); - - intravisit::walk_expr(self, expr); - } - - hir::ExprAssignOp(_, ref lhs, ref rhs) => { - if has_method_map { - self.constrain_call(expr, Some(&lhs), - Some(&**rhs).into_iter(), false); - } - - intravisit::walk_expr(self, expr); - } - - hir::ExprIndex(ref lhs, ref rhs) if has_method_map => { - self.constrain_call(expr, Some(&lhs), - Some(&**rhs).into_iter(), true); - - intravisit::walk_expr(self, expr); - }, - - hir::ExprBinary(op, ref lhs, ref rhs) if has_method_map => { - let implicitly_ref_args = !op.node.is_by_value(); - - // As `expr_method_call`, but the call is via an - // overloaded op. Note that we (sadly) currently use an - // implicit "by ref" sort of passing style here. This - // should be converted to an adjustment! - self.constrain_call(expr, Some(&lhs), - Some(&**rhs).into_iter(), implicitly_ref_args); - - intravisit::walk_expr(self, expr); - } - - hir::ExprBinary(_, ref lhs, ref rhs) => { - // If you do `x OP y`, then the types of `x` and `y` must - // outlive the operation you are performing. - let lhs_ty = self.resolve_expr_type_adjusted(&lhs); - let rhs_ty = self.resolve_expr_type_adjusted(&rhs); - for &ty in &[lhs_ty, rhs_ty] { - self.type_must_outlive(infer::Operand(expr.span), - ty, expr_region); - } - intravisit::walk_expr(self, expr); - } - - hir::ExprUnary(op, ref lhs) if has_method_map => { - let implicitly_ref_args = !op.is_by_value(); - - // As above. - self.constrain_call(expr, Some(&lhs), - None::.iter(), implicitly_ref_args); - - intravisit::walk_expr(self, expr); - } - - hir::ExprUnary(hir::UnDeref, ref base) => { - // For *a, the lifetime of a must enclose the deref - let method_call = MethodCall::expr(expr.id); - let base_ty = match self.tables.borrow().method_map.get(&method_call) { - Some(method) => { - self.constrain_call(expr, Some(&base), - None::.iter(), true); - let fn_ret = // late-bound regions in overloaded method calls are instantiated - self.tcx.no_late_bound_regions(&method.ty.fn_ret()).unwrap(); - fn_ret.unwrap() + hir::ExprCall(ref callee, ref args) => { + if has_method_map { + self.constrain_call(expr, Some(&callee), + args.iter().map(|e| &**e), false); + } else { + self.constrain_callee(callee.id, expr, &callee); + self.constrain_call(expr, None, + args.iter().map(|e| &**e), false); } - None => self.resolve_node_type(base.id) - }; - if let ty::TyRef(r_ptr, _) = base_ty.sty { - self.mk_subregion_due_to_dereference(expr.span, expr_region, *r_ptr); + + intravisit::walk_expr(self, expr); } - intravisit::walk_expr(self, expr); - } + hir::ExprMethodCall(_, _, ref args) => { + self.constrain_call(expr, Some(&args[0]), + args[1..].iter().map(|e| &**e), false); - hir::ExprIndex(ref vec_expr, _) => { - // For a[b], the lifetime of a must enclose the deref - let vec_type = self.resolve_expr_type_adjusted(&vec_expr); - self.constrain_index(expr, vec_type); + intravisit::walk_expr(self, expr); + } - intravisit::walk_expr(self, expr); - } + hir::ExprAssignOp(_, ref lhs, ref rhs) => { + if has_method_map { + self.constrain_call(expr, Some(&lhs), + Some(&**rhs).into_iter(), false); + } - hir::ExprCast(ref source, _) => { - // Determine if we are casting `source` to a trait - // instance. If so, we have to be sure that the type of - // the source obeys the trait's region bound. - self.constrain_cast(expr, &source); - intravisit::walk_expr(self, expr); - } + intravisit::walk_expr(self, expr); + } - hir::ExprAddrOf(m, ref base) => { - self.link_addr_of(expr, m, &base); + hir::ExprIndex(ref lhs, ref rhs) if has_method_map => { + self.constrain_call(expr, Some(&lhs), + Some(&**rhs).into_iter(), true); - // Require that when you write a `&expr` expression, the - // resulting pointer has a lifetime that encompasses the - // `&expr` expression itself. Note that we constraining - // the type of the node expr.id here *before applying - // adjustments*. - // - // FIXME(#6268) nested method calls requires that this rule change - let ty0 = self.resolve_node_type(expr.id); - self.type_must_outlive(infer::AddrOf(expr.span), ty0, expr_region); - intravisit::walk_expr(self, expr); - } + intravisit::walk_expr(self, expr); + }, - hir::ExprMatch(ref discr, ref arms, _) => { - self.link_match(&discr, &arms[..]); + hir::ExprBinary(op, ref lhs, ref rhs) if has_method_map => { + let implicitly_ref_args = !op.node.is_by_value(); - intravisit::walk_expr(self, expr); - } + // As `expr_method_call`, but the call is via an + // overloaded op. Note that we (sadly) currently use an + // implicit "by ref" sort of passing style here. This + // should be converted to an adjustment! + self.constrain_call(expr, Some(&lhs), + Some(&**rhs).into_iter(), implicitly_ref_args); - hir::ExprClosure(_, _, ref body, _) => { - self.check_expr_fn_block(expr, &body); - } + intravisit::walk_expr(self, expr); + } - hir::ExprLoop(ref body, _) => { - let repeating_scope = self.set_repeating_scope(body.id); - intravisit::walk_expr(self, expr); - self.set_repeating_scope(repeating_scope); - } + hir::ExprBinary(_, ref lhs, ref rhs) => { + // If you do `x OP y`, then the types of `x` and `y` must + // outlive the operation you are performing. + let lhs_ty = self.resolve_expr_type_adjusted(&lhs); + let rhs_ty = self.resolve_expr_type_adjusted(&rhs); + for &ty in &[lhs_ty, rhs_ty] { + self.type_must_outlive(infer::Operand(expr.span), + ty, expr_region); + } + intravisit::walk_expr(self, expr); + } - hir::ExprWhile(ref cond, ref body, _) => { - let repeating_scope = self.set_repeating_scope(cond.id); - self.visit_expr(&cond); + hir::ExprUnary(op, ref lhs) if has_method_map => { + let implicitly_ref_args = !op.is_by_value(); - self.set_repeating_scope(body.id); - self.visit_block(&body); + // As above. + self.constrain_call(expr, Some(&lhs), + None::.iter(), implicitly_ref_args); - self.set_repeating_scope(repeating_scope); - } + intravisit::walk_expr(self, expr); + } - hir::ExprRet(Some(ref ret_expr)) => { - let call_site_scope = self.call_site_scope; - debug!("visit_expr ExprRet ret_expr.id {} call_site_scope: {:?}", - ret_expr.id, call_site_scope); - self.type_of_node_must_outlive(infer::CallReturn(ret_expr.span), - ret_expr.id, - ty::ReScope(call_site_scope.unwrap())); - intravisit::walk_expr(self, expr); - } + hir::ExprUnary(hir::UnDeref, ref base) => { + // For *a, the lifetime of a must enclose the deref + let method_call = MethodCall::expr(expr.id); + let base_ty = match self.tables.borrow().method_map.get(&method_call) { + Some(method) => { + self.constrain_call(expr, Some(&base), + None::.iter(), true); + // late-bound regions in overloaded method calls are instantiated + let fn_ret = self.tcx.no_late_bound_regions(&method.ty.fn_ret()); + fn_ret.unwrap().unwrap() + } + None => self.resolve_node_type(base.id) + }; + if let ty::TyRef(r_ptr, _) = base_ty.sty { + self.mk_subregion_due_to_dereference(expr.span, expr_region, *r_ptr); + } - _ => { - intravisit::walk_expr(self, expr); + intravisit::walk_expr(self, expr); + } + + hir::ExprIndex(ref vec_expr, _) => { + // For a[b], the lifetime of a must enclose the deref + let vec_type = self.resolve_expr_type_adjusted(&vec_expr); + self.constrain_index(expr, vec_type); + + intravisit::walk_expr(self, expr); + } + + hir::ExprCast(ref source, _) => { + // Determine if we are casting `source` to a trait + // instance. If so, we have to be sure that the type of + // the source obeys the trait's region bound. + self.constrain_cast(expr, &source); + intravisit::walk_expr(self, expr); + } + + hir::ExprAddrOf(m, ref base) => { + self.link_addr_of(expr, m, &base); + + // Require that when you write a `&expr` expression, the + // resulting pointer has a lifetime that encompasses the + // `&expr` expression itself. Note that we constraining + // the type of the node expr.id here *before applying + // adjustments*. + // + // FIXME(#6268) nested method calls requires that this rule change + let ty0 = self.resolve_node_type(expr.id); + self.type_must_outlive(infer::AddrOf(expr.span), ty0, expr_region); + intravisit::walk_expr(self, expr); + } + + hir::ExprMatch(ref discr, ref arms, _) => { + self.link_match(&discr, &arms[..]); + + intravisit::walk_expr(self, expr); + } + + hir::ExprClosure(_, _, ref body, _) => { + self.check_expr_fn_block(expr, &body); + } + + hir::ExprLoop(ref body, _) => { + let repeating_scope = self.set_repeating_scope(body.id); + intravisit::walk_expr(self, expr); + self.set_repeating_scope(repeating_scope); + } + + hir::ExprWhile(ref cond, ref body, _) => { + let repeating_scope = self.set_repeating_scope(cond.id); + self.visit_expr(&cond); + + self.set_repeating_scope(body.id); + self.visit_block(&body); + + self.set_repeating_scope(repeating_scope); + } + + hir::ExprRet(Some(ref ret_expr)) => { + let call_site_scope = self.call_site_scope; + debug!("visit_expr ExprRet ret_expr.id {} call_site_scope: {:?}", + ret_expr.id, call_site_scope); + self.type_of_node_must_outlive(infer::CallReturn(ret_expr.span), + ret_expr.id, + ty::ReScope(call_site_scope.unwrap())); + intravisit::walk_expr(self, expr); + } + + _ => { + intravisit::walk_expr(self, expr); + } } } } -} impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { -fn constrain_cast(&mut self, - cast_expr: &hir::Expr, - source_expr: &hir::Expr) -{ - debug!("constrain_cast(cast_expr={:?}, source_expr={:?})", - cast_expr, - source_expr); + fn constrain_cast(&mut self, + cast_expr: &hir::Expr, + source_expr: &hir::Expr) + { + debug!("constrain_cast(cast_expr={:?}, source_expr={:?})", + cast_expr, + source_expr); - let source_ty = self.resolve_node_type(source_expr.id); - let target_ty = self.resolve_node_type(cast_expr.id); + let source_ty = self.resolve_node_type(source_expr.id); + let target_ty = self.resolve_node_type(cast_expr.id); - self.walk_cast(cast_expr, source_ty, target_ty); -} + self.walk_cast(cast_expr, source_ty, target_ty); + } fn walk_cast(&mut self, cast_expr: &hir::Expr, @@ -841,984 +841,986 @@ fn constrain_cast(&mut self, } } -fn check_expr_fn_block(&mut self, - expr: &hir::Expr, - body: &hir::Block) { - let repeating_scope = self.set_repeating_scope(body.id); - intravisit::walk_expr(self, expr); - self.set_repeating_scope(repeating_scope); -} - -fn constrain_callee(&mut self, - callee_id: ast::NodeId, - _call_expr: &hir::Expr, - _callee_expr: &hir::Expr) { - let callee_ty = self.resolve_node_type(callee_id); - match callee_ty.sty { - ty::TyFnDef(..) | ty::TyFnPtr(_) => { } - _ => { - // this should not happen, but it does if the program is - // erroneous - // - // bug!( - // callee_expr.span, - // "Calling non-function: {}", - // callee_ty); - } - } -} - -fn constrain_call<'b, I: Iterator>(&mut self, - call_expr: &hir::Expr, - receiver: Option<&hir::Expr>, - arg_exprs: I, - implicitly_ref_args: bool) { - //! Invoked on every call site (i.e., normal calls, method calls, - //! and overloaded operators). Constrains the regions which appear - //! in the type of the function. Also constrains the regions that - //! appear in the arguments appropriately. - - debug!("constrain_call(call_expr={:?}, \ - receiver={:?}, \ - implicitly_ref_args={})", - call_expr, - receiver, - implicitly_ref_args); - - // `callee_region` is the scope representing the time in which the - // call occurs. - // - // FIXME(#6268) to support nested method calls, should be callee_id - let callee_scope = self.tcx.region_maps.node_extent(call_expr.id); - let callee_region = ty::ReScope(callee_scope); - - debug!("callee_region={:?}", callee_region); - - for arg_expr in arg_exprs { - debug!("Argument: {:?}", arg_expr); - - // ensure that any regions appearing in the argument type are - // valid for at least the lifetime of the function: - self.type_of_node_must_outlive(infer::CallArg(arg_expr.span), - arg_expr.id, callee_region); - - // unfortunately, there are two means of taking implicit - // references, and we need to propagate constraints as a - // result. modes are going away and the "DerefArgs" code - // should be ported to use adjustments - if implicitly_ref_args { - self.link_by_ref(arg_expr, callee_scope); - } + fn check_expr_fn_block(&mut self, + expr: &hir::Expr, + body: &hir::Block) { + let repeating_scope = self.set_repeating_scope(body.id); + intravisit::walk_expr(self, expr); + self.set_repeating_scope(repeating_scope); } - // as loop above, but for receiver - if let Some(r) = receiver { - debug!("receiver: {:?}", r); - self.type_of_node_must_outlive(infer::CallRcvr(r.span), - r.id, callee_region); - if implicitly_ref_args { - self.link_by_ref(&r, callee_scope); - } - } -} - -/// Invoked on any auto-dereference that occurs. Checks that if this is a region pointer being -/// dereferenced, the lifetime of the pointer includes the deref expr. -fn constrain_autoderefs(&mut self, - deref_expr: &hir::Expr, - derefs: usize, - mut derefd_ty: Ty<'tcx>) -{ - debug!("constrain_autoderefs(deref_expr={:?}, derefs={}, derefd_ty={:?})", - deref_expr, - derefs, - derefd_ty); - - let s_deref_expr = self.tcx.region_maps.node_extent(deref_expr.id); - let r_deref_expr = ty::ReScope(s_deref_expr); - for i in 0..derefs { - let method_call = MethodCall::autoderef(deref_expr.id, i as u32); - debug!("constrain_autoderefs: method_call={:?} (of {:?} total)", method_call, derefs); - - let method = self.tables.borrow().method_map.get(&method_call).map(|m| m.clone()); - - derefd_ty = match method { - Some(method) => { - debug!("constrain_autoderefs: #{} is overloaded, method={:?}", - i, method); - - let origin = infer::ParameterOrigin::OverloadedDeref; - self.substs_wf_in_scope(origin, method.substs, deref_expr.span, r_deref_expr); - - // Treat overloaded autoderefs as if an AutoRef adjustment - // was applied on the base type, as that is always the case. - let fn_sig = method.ty.fn_sig(); - let fn_sig = // late-bound regions should have been instantiated - self.tcx.no_late_bound_regions(fn_sig).unwrap(); - let self_ty = fn_sig.inputs[0]; - let (m, r) = match self_ty.sty { - ty::TyRef(r, ref m) => (m.mutbl, r), - _ => { - span_bug!( - deref_expr.span, - "bad overloaded deref type {:?}", - method.ty) - } - }; - - debug!("constrain_autoderefs: receiver r={:?} m={:?}", - r, m); - - { - let mc = mc::MemCategorizationContext::new(self); - let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i)); - debug!("constrain_autoderefs: self_cmt={:?}", - self_cmt); - self.link_region(deref_expr.span, r, - ty::BorrowKind::from_mutbl(m), self_cmt); - } - - // Specialized version of constrain_call. - self.type_must_outlive(infer::CallRcvr(deref_expr.span), - self_ty, r_deref_expr); - match fn_sig.output { - ty::FnConverging(return_type) => { - self.type_must_outlive(infer::CallReturn(deref_expr.span), - return_type, r_deref_expr); - return_type - } - ty::FnDiverging => bug!() - } - } - None => derefd_ty - }; - - if let ty::TyRef(r_ptr, _) = derefd_ty.sty { - self.mk_subregion_due_to_dereference(deref_expr.span, - r_deref_expr, *r_ptr); - } - - match derefd_ty.builtin_deref(true, ty::NoPreference) { - Some(mt) => derefd_ty = mt.ty, - /* if this type can't be dereferenced, then there's already an error - in the session saying so. Just bail out for now */ - None => break - } - } -} - -pub fn mk_subregion_due_to_dereference(&mut self, - deref_span: Span, - minimum_lifetime: ty::Region, - maximum_lifetime: ty::Region) { - self.sub_regions(infer::DerefPointer(deref_span), - minimum_lifetime, maximum_lifetime) -} - -fn check_safety_of_rvalue_destructor_if_necessary(&mut self, - cmt: mc::cmt<'tcx>, - span: Span) { - match cmt.cat { - Categorization::Rvalue(region) => { - match region { - ty::ReScope(rvalue_scope) => { - let typ = self.resolve_type(cmt.ty); - dropck::check_safety_of_destructor_if_necessary(self, - typ, - span, - rvalue_scope); - } - ty::ReStatic => {} - region => { - span_bug!(span, - "unexpected rvalue region in rvalue \ - destructor safety checking: `{:?}`", - region); - } + fn constrain_callee(&mut self, + callee_id: ast::NodeId, + _call_expr: &hir::Expr, + _callee_expr: &hir::Expr) { + let callee_ty = self.resolve_node_type(callee_id); + match callee_ty.sty { + ty::TyFnDef(..) | ty::TyFnPtr(_) => { } + _ => { + // this should not happen, but it does if the program is + // erroneous + // + // bug!( + // callee_expr.span, + // "Calling non-function: {}", + // callee_ty); } } - _ => {} } -} -/// Invoked on any index expression that occurs. Checks that if this is a slice being indexed, the -/// lifetime of the pointer includes the deref expr. -fn constrain_index(&mut self, - index_expr: &hir::Expr, - indexed_ty: Ty<'tcx>) -{ - debug!("constrain_index(index_expr=?, indexed_ty={}", - self.ty_to_string(indexed_ty)); + fn constrain_call<'b, I: Iterator>(&mut self, + call_expr: &hir::Expr, + receiver: Option<&hir::Expr>, + arg_exprs: I, + implicitly_ref_args: bool) { + //! Invoked on every call site (i.e., normal calls, method calls, + //! and overloaded operators). Constrains the regions which appear + //! in the type of the function. Also constrains the regions that + //! appear in the arguments appropriately. - let r_index_expr = ty::ReScope(self.tcx.region_maps.node_extent(index_expr.id)); - if let ty::TyRef(r_ptr, mt) = indexed_ty.sty { - match mt.ty.sty { - ty::TySlice(_) | ty::TyStr => { - self.sub_regions(infer::IndexSlice(index_expr.span), - r_index_expr, *r_ptr); + debug!("constrain_call(call_expr={:?}, \ + receiver={:?}, \ + implicitly_ref_args={})", + call_expr, + receiver, + implicitly_ref_args); + + // `callee_region` is the scope representing the time in which the + // call occurs. + // + // FIXME(#6268) to support nested method calls, should be callee_id + let callee_scope = self.tcx.region_maps.node_extent(call_expr.id); + let callee_region = ty::ReScope(callee_scope); + + debug!("callee_region={:?}", callee_region); + + for arg_expr in arg_exprs { + debug!("Argument: {:?}", arg_expr); + + // ensure that any regions appearing in the argument type are + // valid for at least the lifetime of the function: + self.type_of_node_must_outlive(infer::CallArg(arg_expr.span), + arg_expr.id, callee_region); + + // unfortunately, there are two means of taking implicit + // references, and we need to propagate constraints as a + // result. modes are going away and the "DerefArgs" code + // should be ported to use adjustments + if implicitly_ref_args { + self.link_by_ref(arg_expr, callee_scope); + } + } + + // as loop above, but for receiver + if let Some(r) = receiver { + debug!("receiver: {:?}", r); + self.type_of_node_must_outlive(infer::CallRcvr(r.span), + r.id, callee_region); + if implicitly_ref_args { + self.link_by_ref(&r, callee_scope); + } + } + } + + /// Invoked on any auto-dereference that occurs. Checks that if this is a region pointer being + /// dereferenced, the lifetime of the pointer includes the deref expr. + fn constrain_autoderefs(&mut self, + deref_expr: &hir::Expr, + derefs: usize, + mut derefd_ty: Ty<'tcx>) + { + debug!("constrain_autoderefs(deref_expr={:?}, derefs={}, derefd_ty={:?})", + deref_expr, + derefs, + derefd_ty); + + let s_deref_expr = self.tcx.region_maps.node_extent(deref_expr.id); + let r_deref_expr = ty::ReScope(s_deref_expr); + for i in 0..derefs { + let method_call = MethodCall::autoderef(deref_expr.id, i as u32); + debug!("constrain_autoderefs: method_call={:?} (of {:?} total)", method_call, derefs); + + let method = self.tables.borrow().method_map.get(&method_call).map(|m| m.clone()); + + derefd_ty = match method { + Some(method) => { + debug!("constrain_autoderefs: #{} is overloaded, method={:?}", + i, method); + + let origin = infer::ParameterOrigin::OverloadedDeref; + self.substs_wf_in_scope(origin, method.substs, deref_expr.span, r_deref_expr); + + // Treat overloaded autoderefs as if an AutoRef adjustment + // was applied on the base type, as that is always the case. + let fn_sig = method.ty.fn_sig(); + let fn_sig = // late-bound regions should have been instantiated + self.tcx.no_late_bound_regions(fn_sig).unwrap(); + let self_ty = fn_sig.inputs[0]; + let (m, r) = match self_ty.sty { + ty::TyRef(r, ref m) => (m.mutbl, r), + _ => { + span_bug!( + deref_expr.span, + "bad overloaded deref type {:?}", + method.ty) + } + }; + + debug!("constrain_autoderefs: receiver r={:?} m={:?}", + r, m); + + { + let mc = mc::MemCategorizationContext::new(self); + let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i)); + debug!("constrain_autoderefs: self_cmt={:?}", + self_cmt); + self.link_region(deref_expr.span, r, + ty::BorrowKind::from_mutbl(m), self_cmt); + } + + // Specialized version of constrain_call. + self.type_must_outlive(infer::CallRcvr(deref_expr.span), + self_ty, r_deref_expr); + match fn_sig.output { + ty::FnConverging(return_type) => { + self.type_must_outlive(infer::CallReturn(deref_expr.span), + return_type, r_deref_expr); + return_type + } + ty::FnDiverging => bug!() + } + } + None => derefd_ty + }; + + if let ty::TyRef(r_ptr, _) = derefd_ty.sty { + self.mk_subregion_due_to_dereference(deref_expr.span, + r_deref_expr, *r_ptr); + } + + match derefd_ty.builtin_deref(true, ty::NoPreference) { + Some(mt) => derefd_ty = mt.ty, + /* if this type can't be dereferenced, then there's already an error + in the session saying so. Just bail out for now */ + None => break + } + } + } + + pub fn mk_subregion_due_to_dereference(&mut self, + deref_span: Span, + minimum_lifetime: ty::Region, + maximum_lifetime: ty::Region) { + self.sub_regions(infer::DerefPointer(deref_span), + minimum_lifetime, maximum_lifetime) + } + + fn check_safety_of_rvalue_destructor_if_necessary(&mut self, + cmt: mc::cmt<'tcx>, + span: Span) { + match cmt.cat { + Categorization::Rvalue(region) => { + match region { + ty::ReScope(rvalue_scope) => { + let typ = self.resolve_type(cmt.ty); + dropck::check_safety_of_destructor_if_necessary(self, + typ, + span, + rvalue_scope); + } + ty::ReStatic => {} + region => { + span_bug!(span, + "unexpected rvalue region in rvalue \ + destructor safety checking: `{:?}`", + region); + } + } } _ => {} } } -} -/// Guarantees that any lifetimes which appear in the type of the node `id` (after applying -/// adjustments) are valid for at least `minimum_lifetime` -fn type_of_node_must_outlive(&mut self, - origin: infer::SubregionOrigin<'tcx>, - id: ast::NodeId, - minimum_lifetime: ty::Region) -{ - let tcx = self.tcx; + /// Invoked on any index expression that occurs. Checks that if this is a slice + /// being indexed, the lifetime of the pointer includes the deref expr. + fn constrain_index(&mut self, + index_expr: &hir::Expr, + indexed_ty: Ty<'tcx>) + { + debug!("constrain_index(index_expr=?, indexed_ty={}", + self.ty_to_string(indexed_ty)); - // Try to resolve the type. If we encounter an error, then typeck - // is going to fail anyway, so just stop here and let typeck - // report errors later on in the writeback phase. - let ty0 = self.resolve_node_type(id); - let ty = ty0.adjust(tcx, origin.span(), id, - self.tables.borrow().adjustments.get(&id), - |method_call| self.resolve_method_type(method_call)); - debug!("constrain_regions_in_type_of_node(\ - ty={}, ty0={}, id={}, minimum_lifetime={:?})", - ty, ty0, - id, minimum_lifetime); - self.type_must_outlive(origin, ty, minimum_lifetime); -} - -/// Computes the guarantor for an expression `&base` and then ensures that the lifetime of the -/// resulting pointer is linked to the lifetime of its guarantor (if any). -fn link_addr_of(&mut self, expr: &hir::Expr, - mutability: hir::Mutability, base: &hir::Expr) { - debug!("link_addr_of(expr={:?}, base={:?})", expr, base); - - let cmt = { - let mc = mc::MemCategorizationContext::new(self); - ignore_err!(mc.cat_expr(base)) - }; - - debug!("link_addr_of: cmt={:?}", cmt); - - self.link_region_from_node_type(expr.span, expr.id, mutability, cmt); -} - -/// Computes the guarantors for any ref bindings in a `let` and -/// then ensures that the lifetime of the resulting pointer is -/// linked to the lifetime of the initialization expression. -fn link_local(&self, local: &hir::Local) { - debug!("regionck::for_local()"); - let init_expr = match local.init { - None => { return; } - Some(ref expr) => &**expr, - }; - let mc = mc::MemCategorizationContext::new(self); - let discr_cmt = ignore_err!(mc.cat_expr(init_expr)); - self.link_pattern(mc, discr_cmt, &local.pat); -} - -/// Computes the guarantors for any ref bindings in a match and -/// then ensures that the lifetime of the resulting pointer is -/// linked to the lifetime of its guarantor (if any). -fn link_match(&self, discr: &hir::Expr, arms: &[hir::Arm]) { - debug!("regionck::for_match()"); - let mc = mc::MemCategorizationContext::new(self); - let discr_cmt = ignore_err!(mc.cat_expr(discr)); - debug!("discr_cmt={:?}", discr_cmt); - for arm in arms { - for root_pat in &arm.pats { - self.link_pattern(mc, discr_cmt.clone(), &root_pat); - } - } -} - -/// Computes the guarantors for any ref bindings in a match and -/// then ensures that the lifetime of the resulting pointer is -/// linked to the lifetime of its guarantor (if any). -fn link_fn_args(&self, body_scope: CodeExtent, args: &[hir::Arg]) { - debug!("regionck::link_fn_args(body_scope={:?})", body_scope); - let mc = mc::MemCategorizationContext::new(self); - for arg in args { - let arg_ty = self.node_ty(arg.id); - let re_scope = ty::ReScope(body_scope); - let arg_cmt = mc.cat_rvalue(arg.id, arg.ty.span, re_scope, arg_ty); - debug!("arg_ty={:?} arg_cmt={:?} arg={:?}", - arg_ty, - arg_cmt, - arg); - self.link_pattern(mc, arg_cmt, &arg.pat); - } -} - -/// Link lifetimes of any ref bindings in `root_pat` to the pointers found in the discriminant, if -/// needed. -fn link_pattern<'t>(&self, - mc: mc::MemCategorizationContext<'a, 'gcx, 'tcx>, - discr_cmt: mc::cmt<'tcx>, - root_pat: &hir::Pat) { - debug!("link_pattern(discr_cmt={:?}, root_pat={:?})", - discr_cmt, - root_pat); - let _ = mc.cat_pattern(discr_cmt, root_pat, |mc, sub_cmt, sub_pat| { - match sub_pat.node { - // `ref x` pattern - PatKind::Ident(hir::BindByRef(mutbl), _, _) => { - self.link_region_from_node_type(sub_pat.span, sub_pat.id, - mutbl, sub_cmt); - } - - // `[_, ..slice, _]` pattern - PatKind::Vec(_, Some(ref slice_pat), _) => { - match mc.cat_slice_pattern(sub_cmt, &slice_pat) { - Ok((slice_cmt, slice_mutbl, slice_r)) => { - self.link_region(sub_pat.span, &slice_r, - ty::BorrowKind::from_mutbl(slice_mutbl), - slice_cmt); - } - Err(()) => {} - } + let r_index_expr = ty::ReScope(self.tcx.region_maps.node_extent(index_expr.id)); + if let ty::TyRef(r_ptr, mt) = indexed_ty.sty { + match mt.ty.sty { + ty::TySlice(_) | ty::TyStr => { + self.sub_regions(infer::IndexSlice(index_expr.span), + r_index_expr, *r_ptr); } _ => {} } - }); -} - -/// Link lifetime of borrowed pointer resulting from autoref to lifetimes in the value being -/// autoref'd. -fn link_autoref(&self, - expr: &hir::Expr, - autoderefs: usize, - autoref: &adjustment::AutoRef) -{ - debug!("link_autoref(autoref={:?})", autoref); - let mc = mc::MemCategorizationContext::new(self); - let expr_cmt = ignore_err!(mc.cat_expr_autoderefd(expr, autoderefs)); - debug!("expr_cmt={:?}", expr_cmt); - - match *autoref { - adjustment::AutoPtr(r, m) => { - self.link_region(expr.span, r, - ty::BorrowKind::from_mutbl(m), expr_cmt); - } - - adjustment::AutoUnsafe(m) => { - let r = ty::ReScope(self.tcx.region_maps.node_extent(expr.id)); - self.link_region(expr.span, &r, ty::BorrowKind::from_mutbl(m), expr_cmt); } } -} -/// Computes the guarantor for cases where the `expr` is being passed by implicit reference and -/// must outlive `callee_scope`. -fn link_by_ref(&self, - expr: &hir::Expr, - callee_scope: CodeExtent) { - debug!("link_by_ref(expr={:?}, callee_scope={:?})", - expr, callee_scope); - let mc = mc::MemCategorizationContext::new(self); - let expr_cmt = ignore_err!(mc.cat_expr(expr)); - let borrow_region = ty::ReScope(callee_scope); - self.link_region(expr.span, &borrow_region, ty::ImmBorrow, expr_cmt); -} + /// Guarantees that any lifetimes which appear in the type of the node `id` (after applying + /// adjustments) are valid for at least `minimum_lifetime` + fn type_of_node_must_outlive(&mut self, + origin: infer::SubregionOrigin<'tcx>, + id: ast::NodeId, + minimum_lifetime: ty::Region) + { + let tcx = self.tcx; -/// Like `link_region()`, except that the region is extracted from the type of `id`, which must be -/// some reference (`&T`, `&str`, etc). -fn link_region_from_node_type(&self, - span: Span, - id: ast::NodeId, - mutbl: hir::Mutability, - cmt_borrowed: mc::cmt<'tcx>) { - debug!("link_region_from_node_type(id={:?}, mutbl={:?}, cmt_borrowed={:?})", - id, mutbl, cmt_borrowed); - - let rptr_ty = self.resolve_node_type(id); - if let ty::TyRef(&r, _) = rptr_ty.sty { - debug!("rptr_ty={}", rptr_ty); - self.link_region(span, &r, ty::BorrowKind::from_mutbl(mutbl), - cmt_borrowed); + // Try to resolve the type. If we encounter an error, then typeck + // is going to fail anyway, so just stop here and let typeck + // report errors later on in the writeback phase. + let ty0 = self.resolve_node_type(id); + let ty = ty0.adjust(tcx, origin.span(), id, + self.tables.borrow().adjustments.get(&id), + |method_call| self.resolve_method_type(method_call)); + debug!("constrain_regions_in_type_of_node(\ + ty={}, ty0={}, id={}, minimum_lifetime={:?})", + ty, ty0, + id, minimum_lifetime); + self.type_must_outlive(origin, ty, minimum_lifetime); } -} -/// Informs the inference engine that `borrow_cmt` is being borrowed with kind `borrow_kind` and -/// lifetime `borrow_region`. In order to ensure borrowck is satisfied, this may create constraints -/// between regions, as explained in `link_reborrowed_region()`. -fn link_region(&self, - span: Span, - borrow_region: &ty::Region, - borrow_kind: ty::BorrowKind, - borrow_cmt: mc::cmt<'tcx>) { - let mut borrow_cmt = borrow_cmt; - let mut borrow_kind = borrow_kind; + /// Computes the guarantor for an expression `&base` and then ensures that the lifetime of the + /// resulting pointer is linked to the lifetime of its guarantor (if any). + fn link_addr_of(&mut self, expr: &hir::Expr, + mutability: hir::Mutability, base: &hir::Expr) { + debug!("link_addr_of(expr={:?}, base={:?})", expr, base); - let origin = infer::DataBorrowed(borrow_cmt.ty, span); - self.type_must_outlive(origin, borrow_cmt.ty, *borrow_region); + let cmt = { + let mc = mc::MemCategorizationContext::new(self); + ignore_err!(mc.cat_expr(base)) + }; - loop { - debug!("link_region(borrow_region={:?}, borrow_kind={:?}, borrow_cmt={:?})", - borrow_region, - borrow_kind, - borrow_cmt); - match borrow_cmt.cat.clone() { - Categorization::Deref(ref_cmt, _, - mc::Implicit(ref_kind, ref_region)) | - Categorization::Deref(ref_cmt, _, - mc::BorrowedPtr(ref_kind, ref_region)) => { - match self.link_reborrowed_region(span, - borrow_region, borrow_kind, - ref_cmt, ref_region, ref_kind, - borrow_cmt.note) { - Some((c, k)) => { - borrow_cmt = c; - borrow_kind = k; + debug!("link_addr_of: cmt={:?}", cmt); + + self.link_region_from_node_type(expr.span, expr.id, mutability, cmt); + } + + /// Computes the guarantors for any ref bindings in a `let` and + /// then ensures that the lifetime of the resulting pointer is + /// linked to the lifetime of the initialization expression. + fn link_local(&self, local: &hir::Local) { + debug!("regionck::for_local()"); + let init_expr = match local.init { + None => { return; } + Some(ref expr) => &**expr, + }; + let mc = mc::MemCategorizationContext::new(self); + let discr_cmt = ignore_err!(mc.cat_expr(init_expr)); + self.link_pattern(mc, discr_cmt, &local.pat); + } + + /// Computes the guarantors for any ref bindings in a match and + /// then ensures that the lifetime of the resulting pointer is + /// linked to the lifetime of its guarantor (if any). + fn link_match(&self, discr: &hir::Expr, arms: &[hir::Arm]) { + debug!("regionck::for_match()"); + let mc = mc::MemCategorizationContext::new(self); + let discr_cmt = ignore_err!(mc.cat_expr(discr)); + debug!("discr_cmt={:?}", discr_cmt); + for arm in arms { + for root_pat in &arm.pats { + self.link_pattern(mc, discr_cmt.clone(), &root_pat); + } + } + } + + /// Computes the guarantors for any ref bindings in a match and + /// then ensures that the lifetime of the resulting pointer is + /// linked to the lifetime of its guarantor (if any). + fn link_fn_args(&self, body_scope: CodeExtent, args: &[hir::Arg]) { + debug!("regionck::link_fn_args(body_scope={:?})", body_scope); + let mc = mc::MemCategorizationContext::new(self); + for arg in args { + let arg_ty = self.node_ty(arg.id); + let re_scope = ty::ReScope(body_scope); + let arg_cmt = mc.cat_rvalue(arg.id, arg.ty.span, re_scope, arg_ty); + debug!("arg_ty={:?} arg_cmt={:?} arg={:?}", + arg_ty, + arg_cmt, + arg); + self.link_pattern(mc, arg_cmt, &arg.pat); + } + } + + /// Link lifetimes of any ref bindings in `root_pat` to the pointers found + /// in the discriminant, if needed. + fn link_pattern<'t>(&self, + mc: mc::MemCategorizationContext<'a, 'gcx, 'tcx>, + discr_cmt: mc::cmt<'tcx>, + root_pat: &hir::Pat) { + debug!("link_pattern(discr_cmt={:?}, root_pat={:?})", + discr_cmt, + root_pat); + let _ = mc.cat_pattern(discr_cmt, root_pat, |mc, sub_cmt, sub_pat| { + match sub_pat.node { + // `ref x` pattern + PatKind::Ident(hir::BindByRef(mutbl), _, _) => { + self.link_region_from_node_type(sub_pat.span, sub_pat.id, + mutbl, sub_cmt); } - None => { - return; + + // `[_, ..slice, _]` pattern + PatKind::Vec(_, Some(ref slice_pat), _) => { + match mc.cat_slice_pattern(sub_cmt, &slice_pat) { + Ok((slice_cmt, slice_mutbl, slice_r)) => { + self.link_region(sub_pat.span, &slice_r, + ty::BorrowKind::from_mutbl(slice_mutbl), + slice_cmt); + } + Err(()) => {} + } + } + _ => {} + } + }); + } + + /// Link lifetime of borrowed pointer resulting from autoref to lifetimes in the value being + /// autoref'd. + fn link_autoref(&self, + expr: &hir::Expr, + autoderefs: usize, + autoref: &adjustment::AutoRef) + { + debug!("link_autoref(autoref={:?})", autoref); + let mc = mc::MemCategorizationContext::new(self); + let expr_cmt = ignore_err!(mc.cat_expr_autoderefd(expr, autoderefs)); + debug!("expr_cmt={:?}", expr_cmt); + + match *autoref { + adjustment::AutoPtr(r, m) => { + self.link_region(expr.span, r, + ty::BorrowKind::from_mutbl(m), expr_cmt); + } + + adjustment::AutoUnsafe(m) => { + let r = ty::ReScope(self.tcx.region_maps.node_extent(expr.id)); + self.link_region(expr.span, &r, ty::BorrowKind::from_mutbl(m), expr_cmt); + } + } + } + + /// Computes the guarantor for cases where the `expr` is being passed by implicit reference and + /// must outlive `callee_scope`. + fn link_by_ref(&self, + expr: &hir::Expr, + callee_scope: CodeExtent) { + debug!("link_by_ref(expr={:?}, callee_scope={:?})", + expr, callee_scope); + let mc = mc::MemCategorizationContext::new(self); + let expr_cmt = ignore_err!(mc.cat_expr(expr)); + let borrow_region = ty::ReScope(callee_scope); + self.link_region(expr.span, &borrow_region, ty::ImmBorrow, expr_cmt); + } + + /// Like `link_region()`, except that the region is extracted from the type of `id`, + /// which must be some reference (`&T`, `&str`, etc). + fn link_region_from_node_type(&self, + span: Span, + id: ast::NodeId, + mutbl: hir::Mutability, + cmt_borrowed: mc::cmt<'tcx>) { + debug!("link_region_from_node_type(id={:?}, mutbl={:?}, cmt_borrowed={:?})", + id, mutbl, cmt_borrowed); + + let rptr_ty = self.resolve_node_type(id); + if let ty::TyRef(&r, _) = rptr_ty.sty { + debug!("rptr_ty={}", rptr_ty); + self.link_region(span, &r, ty::BorrowKind::from_mutbl(mutbl), + cmt_borrowed); + } + } + + /// Informs the inference engine that `borrow_cmt` is being borrowed with + /// kind `borrow_kind` and lifetime `borrow_region`. + /// In order to ensure borrowck is satisfied, this may create constraints + /// between regions, as explained in `link_reborrowed_region()`. + fn link_region(&self, + span: Span, + borrow_region: &ty::Region, + borrow_kind: ty::BorrowKind, + borrow_cmt: mc::cmt<'tcx>) { + let mut borrow_cmt = borrow_cmt; + let mut borrow_kind = borrow_kind; + + let origin = infer::DataBorrowed(borrow_cmt.ty, span); + self.type_must_outlive(origin, borrow_cmt.ty, *borrow_region); + + loop { + debug!("link_region(borrow_region={:?}, borrow_kind={:?}, borrow_cmt={:?})", + borrow_region, + borrow_kind, + borrow_cmt); + match borrow_cmt.cat.clone() { + Categorization::Deref(ref_cmt, _, + mc::Implicit(ref_kind, ref_region)) | + Categorization::Deref(ref_cmt, _, + mc::BorrowedPtr(ref_kind, ref_region)) => { + match self.link_reborrowed_region(span, + borrow_region, borrow_kind, + ref_cmt, ref_region, ref_kind, + borrow_cmt.note) { + Some((c, k)) => { + borrow_cmt = c; + borrow_kind = k; + } + None => { + return; + } + } + } + + Categorization::Downcast(cmt_base, _) | + Categorization::Deref(cmt_base, _, mc::Unique) | + Categorization::Interior(cmt_base, _) => { + // Borrowing interior or owned data requires the base + // to be valid and borrowable in the same fashion. + borrow_cmt = cmt_base; + borrow_kind = borrow_kind; + } + + Categorization::Deref(_, _, mc::UnsafePtr(..)) | + Categorization::StaticItem | + Categorization::Upvar(..) | + Categorization::Local(..) | + Categorization::Rvalue(..) => { + // These are all "base cases" with independent lifetimes + // that are not subject to inference + return; + } + } + } + } + + /// This is the most complicated case: the path being borrowed is + /// itself the referent of a borrowed pointer. Let me give an + /// example fragment of code to make clear(er) the situation: + /// + /// let r: &'a mut T = ...; // the original reference "r" has lifetime 'a + /// ... + /// &'z *r // the reborrow has lifetime 'z + /// + /// Now, in this case, our primary job is to add the inference + /// constraint that `'z <= 'a`. Given this setup, let's clarify the + /// parameters in (roughly) terms of the example: + /// + /// A borrow of: `& 'z bk * r` where `r` has type `& 'a bk T` + /// borrow_region ^~ ref_region ^~ + /// borrow_kind ^~ ref_kind ^~ + /// ref_cmt ^ + /// + /// Here `bk` stands for some borrow-kind (e.g., `mut`, `uniq`, etc). + /// + /// Unfortunately, there are some complications beyond the simple + /// scenario I just painted: + /// + /// 1. The reference `r` might in fact be a "by-ref" upvar. In that + /// case, we have two jobs. First, we are inferring whether this reference + /// should be an `&T`, `&mut T`, or `&uniq T` reference, and we must + /// adjust that based on this borrow (e.g., if this is an `&mut` borrow, + /// then `r` must be an `&mut` reference). Second, whenever we link + /// two regions (here, `'z <= 'a`), we supply a *cause*, and in this + /// case we adjust the cause to indicate that the reference being + /// "reborrowed" is itself an upvar. This provides a nicer error message + /// should something go wrong. + /// + /// 2. There may in fact be more levels of reborrowing. In the + /// example, I said the borrow was like `&'z *r`, but it might + /// in fact be a borrow like `&'z **q` where `q` has type `&'a + /// &'b mut T`. In that case, we want to ensure that `'z <= 'a` + /// and `'z <= 'b`. This is explained more below. + /// + /// The return value of this function indicates whether we need to + /// recurse and process `ref_cmt` (see case 2 above). + fn link_reborrowed_region(&self, + span: Span, + borrow_region: &ty::Region, + borrow_kind: ty::BorrowKind, + ref_cmt: mc::cmt<'tcx>, + ref_region: ty::Region, + mut ref_kind: ty::BorrowKind, + note: mc::Note) + -> Option<(mc::cmt<'tcx>, ty::BorrowKind)> + { + // Possible upvar ID we may need later to create an entry in the + // maybe link map. + + // Detect by-ref upvar `x`: + let cause = match note { + mc::NoteUpvarRef(ref upvar_id) => { + let upvar_capture_map = &self.tables.borrow_mut().upvar_capture_map; + match upvar_capture_map.get(upvar_id) { + Some(&ty::UpvarCapture::ByRef(ref upvar_borrow)) => { + // The mutability of the upvar may have been modified + // by the above adjustment, so update our local variable. + ref_kind = upvar_borrow.kind; + + infer::ReborrowUpvar(span, *upvar_id) + } + _ => { + span_bug!( span, "Illegal upvar id: {:?}", upvar_id); } } } + mc::NoteClosureEnv(ref upvar_id) => { + // We don't have any mutability changes to propagate, but + // we do want to note that an upvar reborrow caused this + // link + infer::ReborrowUpvar(span, *upvar_id) + } + _ => { + infer::Reborrow(span) + } + }; - Categorization::Downcast(cmt_base, _) | - Categorization::Deref(cmt_base, _, mc::Unique) | - Categorization::Interior(cmt_base, _) => { - // Borrowing interior or owned data requires the base - // to be valid and borrowable in the same fashion. - borrow_cmt = cmt_base; - borrow_kind = borrow_kind; + debug!("link_reborrowed_region: {:?} <= {:?}", + borrow_region, + ref_region); + self.sub_regions(cause, *borrow_region, ref_region); + + // If we end up needing to recurse and establish a region link + // with `ref_cmt`, calculate what borrow kind we will end up + // needing. This will be used below. + // + // One interesting twist is that we can weaken the borrow kind + // when we recurse: to reborrow an `&mut` referent as mutable, + // borrowck requires a unique path to the `&mut` reference but not + // necessarily a *mutable* path. + let new_borrow_kind = match borrow_kind { + ty::ImmBorrow => + ty::ImmBorrow, + ty::MutBorrow | ty::UniqueImmBorrow => + ty::UniqueImmBorrow + }; + + // Decide whether we need to recurse and link any regions within + // the `ref_cmt`. This is concerned for the case where the value + // being reborrowed is in fact a borrowed pointer found within + // another borrowed pointer. For example: + // + // let p: &'b &'a mut T = ...; + // ... + // &'z **p + // + // What makes this case particularly tricky is that, if the data + // being borrowed is a `&mut` or `&uniq` borrow, borrowck requires + // not only that `'z <= 'a`, (as before) but also `'z <= 'b` + // (otherwise the user might mutate through the `&mut T` reference + // after `'b` expires and invalidate the borrow we are looking at + // now). + // + // So let's re-examine our parameters in light of this more + // complicated (possible) scenario: + // + // A borrow of: `& 'z bk * * p` where `p` has type `&'b bk & 'a bk T` + // borrow_region ^~ ref_region ^~ + // borrow_kind ^~ ref_kind ^~ + // ref_cmt ^~~ + // + // (Note that since we have not examined `ref_cmt.cat`, we don't + // know whether this scenario has occurred; but I wanted to show + // how all the types get adjusted.) + match ref_kind { + ty::ImmBorrow => { + // The reference being reborrowed is a sharable ref of + // type `&'a T`. In this case, it doesn't matter where we + // *found* the `&T` pointer, the memory it references will + // be valid and immutable for `'a`. So we can stop here. + // + // (Note that the `borrow_kind` must also be ImmBorrow or + // else the user is borrowed imm memory as mut memory, + // which means they'll get an error downstream in borrowck + // anyhow.) + return None; } - Categorization::Deref(_, _, mc::UnsafePtr(..)) | - Categorization::StaticItem | - Categorization::Upvar(..) | - Categorization::Local(..) | - Categorization::Rvalue(..) => { - // These are all "base cases" with independent lifetimes - // that are not subject to inference + ty::MutBorrow | ty::UniqueImmBorrow => { + // The reference being reborrowed is either an `&mut T` or + // `&uniq T`. This is the case where recursion is needed. + return Some((ref_cmt, new_borrow_kind)); + } + } + } + + /// Checks that the values provided for type/region arguments in a given + /// expression are well-formed and in-scope. + fn substs_wf_in_scope(&mut self, + origin: infer::ParameterOrigin, + substs: &Substs<'tcx>, + expr_span: Span, + expr_region: ty::Region) { + debug!("substs_wf_in_scope(substs={:?}, \ + expr_region={:?}, \ + origin={:?}, \ + expr_span={:?})", + substs, expr_region, origin, expr_span); + + let origin = infer::ParameterInScope(origin, expr_span); + + for ®ion in &substs.regions { + self.sub_regions(origin.clone(), expr_region, region); + } + + for &ty in &substs.types { + let ty = self.resolve_type(ty); + self.type_must_outlive(origin.clone(), ty, expr_region); + } + } + + /// Ensures that type is well-formed in `region`, which implies (among + /// other things) that all borrowed data reachable via `ty` outlives + /// `region`. + pub fn type_must_outlive(&self, + origin: infer::SubregionOrigin<'tcx>, + ty: Ty<'tcx>, + region: ty::Region) + { + let ty = self.resolve_type(ty); + + debug!("type_must_outlive(ty={:?}, region={:?}, origin={:?})", + ty, + region, + origin); + + assert!(!ty.has_escaping_regions()); + + let components = self.outlives_components(ty); + self.components_must_outlive(origin, components, region); + } + + fn components_must_outlive(&self, + origin: infer::SubregionOrigin<'tcx>, + components: Vec>, + region: ty::Region) + { + for component in components { + let origin = origin.clone(); + match component { + ty::outlives::Component::Region(region1) => { + self.sub_regions(origin, region, region1); + } + ty::outlives::Component::Param(param_ty) => { + self.param_ty_must_outlive(origin, region, param_ty); + } + ty::outlives::Component::Projection(projection_ty) => { + self.projection_must_outlive(origin, region, projection_ty); + } + ty::outlives::Component::EscapingProjection(subcomponents) => { + self.components_must_outlive(origin, subcomponents, region); + } + ty::outlives::Component::UnresolvedInferenceVariable(v) => { + // ignore this, we presume it will yield an error + // later, since if a type variable is not resolved by + // this point it never will be + self.tcx.sess.delay_span_bug( + origin.span(), + &format!("unresolved inference variable in outlives: {:?}", v)); + } + } + } + } + + fn param_ty_must_outlive(&self, + origin: infer::SubregionOrigin<'tcx>, + region: ty::Region, + param_ty: ty::ParamTy) { + debug!("param_ty_must_outlive(region={:?}, param_ty={:?}, origin={:?})", + region, param_ty, origin); + + let verify_bound = self.param_bound(param_ty); + let generic = GenericKind::Param(param_ty); + self.verify_generic_bound(origin, generic, region, verify_bound); + } + + fn projection_must_outlive(&self, + origin: infer::SubregionOrigin<'tcx>, + region: ty::Region, + projection_ty: ty::ProjectionTy<'tcx>) + { + debug!("projection_must_outlive(region={:?}, projection_ty={:?}, origin={:?})", + region, projection_ty, origin); + + // This case is thorny for inference. The fundamental problem is + // that there are many cases where we have choice, and inference + // doesn't like choice (the current region inference in + // particular). :) First off, we have to choose between using the + // OutlivesProjectionEnv, OutlivesProjectionTraitDef, and + // OutlivesProjectionComponent rules, any one of which is + // sufficient. If there are no inference variables involved, it's + // not hard to pick the right rule, but if there are, we're in a + // bit of a catch 22: if we picked which rule we were going to + // use, we could add constraints to the region inference graph + // that make it apply, but if we don't add those constraints, the + // rule might not apply (but another rule might). For now, we err + // on the side of adding too few edges into the graph. + + // Compute the bounds we can derive from the environment or trait + // definition. We know that the projection outlives all the + // regions in this list. + let env_bounds = self.projection_declared_bounds(origin.span(), projection_ty); + + debug!("projection_must_outlive: env_bounds={:?}", + env_bounds); + + // If we know that the projection outlives 'static, then we're + // done here. + if env_bounds.contains(&ty::ReStatic) { + debug!("projection_must_outlive: 'static as declared bound"); + return; + } + + // If declared bounds list is empty, the only applicable rule is + // OutlivesProjectionComponent. If there are inference variables, + // then, we can break down the outlives into more primitive + // components without adding unnecessary edges. + // + // If there are *no* inference variables, however, we COULD do + // this, but we choose not to, because the error messages are less + // good. For example, a requirement like `T::Item: 'r` would be + // translated to a requirement that `T: 'r`; when this is reported + // to the user, it will thus say "T: 'r must hold so that T::Item: + // 'r holds". But that makes it sound like the only way to fix + // the problem is to add `T: 'r`, which isn't true. So, if there are no + // inference variables, we use a verify constraint instead of adding + // edges, which winds up enforcing the same condition. + let needs_infer = { + projection_ty.trait_ref.substs.types.iter().any(|t| t.needs_infer()) || + projection_ty.trait_ref.substs.regions.iter().any(|r| r.needs_infer()) + }; + if env_bounds.is_empty() && needs_infer { + debug!("projection_must_outlive: no declared bounds"); + + for &component_ty in &projection_ty.trait_ref.substs.types { + self.type_must_outlive(origin.clone(), component_ty, region); + } + + for &r in &projection_ty.trait_ref.substs.regions { + self.sub_regions(origin.clone(), region, r); + } + + return; + } + + // If we find that there is a unique declared bound `'b`, and this bound + // appears in the trait reference, then the best action is to require that `'b:'r`, + // so do that. This is best no matter what rule we use: + // + // - OutlivesProjectionEnv or OutlivesProjectionTraitDef: these would translate to + // the requirement that `'b:'r` + // - OutlivesProjectionComponent: this would require `'b:'r` in addition to + // other conditions + if !env_bounds.is_empty() && env_bounds[1..].iter().all(|b| *b == env_bounds[0]) { + let unique_bound = env_bounds[0]; + debug!("projection_must_outlive: unique declared bound = {:?}", unique_bound); + if projection_ty.trait_ref.substs.regions + .iter() + .any(|r| env_bounds.contains(r)) + { + debug!("projection_must_outlive: unique declared bound appears in trait ref"); + self.sub_regions(origin.clone(), region, unique_bound); return; } } - } -} -/// This is the most complicated case: the path being borrowed is -/// itself the referent of a borrowed pointer. Let me give an -/// example fragment of code to make clear(er) the situation: -/// -/// let r: &'a mut T = ...; // the original reference "r" has lifetime 'a -/// ... -/// &'z *r // the reborrow has lifetime 'z -/// -/// Now, in this case, our primary job is to add the inference -/// constraint that `'z <= 'a`. Given this setup, let's clarify the -/// parameters in (roughly) terms of the example: -/// -/// A borrow of: `& 'z bk * r` where `r` has type `& 'a bk T` -/// borrow_region ^~ ref_region ^~ -/// borrow_kind ^~ ref_kind ^~ -/// ref_cmt ^ -/// -/// Here `bk` stands for some borrow-kind (e.g., `mut`, `uniq`, etc). -/// -/// Unfortunately, there are some complications beyond the simple -/// scenario I just painted: -/// -/// 1. The reference `r` might in fact be a "by-ref" upvar. In that -/// case, we have two jobs. First, we are inferring whether this reference -/// should be an `&T`, `&mut T`, or `&uniq T` reference, and we must -/// adjust that based on this borrow (e.g., if this is an `&mut` borrow, -/// then `r` must be an `&mut` reference). Second, whenever we link -/// two regions (here, `'z <= 'a`), we supply a *cause*, and in this -/// case we adjust the cause to indicate that the reference being -/// "reborrowed" is itself an upvar. This provides a nicer error message -/// should something go wrong. -/// -/// 2. There may in fact be more levels of reborrowing. In the -/// example, I said the borrow was like `&'z *r`, but it might -/// in fact be a borrow like `&'z **q` where `q` has type `&'a -/// &'b mut T`. In that case, we want to ensure that `'z <= 'a` -/// and `'z <= 'b`. This is explained more below. -/// -/// The return value of this function indicates whether we need to -/// recurse and process `ref_cmt` (see case 2 above). -fn link_reborrowed_region(&self, - span: Span, - borrow_region: &ty::Region, - borrow_kind: ty::BorrowKind, - ref_cmt: mc::cmt<'tcx>, - ref_region: ty::Region, - mut ref_kind: ty::BorrowKind, - note: mc::Note) - -> Option<(mc::cmt<'tcx>, ty::BorrowKind)> -{ - // Possible upvar ID we may need later to create an entry in the - // maybe link map. - - // Detect by-ref upvar `x`: - let cause = match note { - mc::NoteUpvarRef(ref upvar_id) => { - let upvar_capture_map = &self.tables.borrow_mut().upvar_capture_map; - match upvar_capture_map.get(upvar_id) { - Some(&ty::UpvarCapture::ByRef(ref upvar_borrow)) => { - // The mutability of the upvar may have been modified - // by the above adjustment, so update our local variable. - ref_kind = upvar_borrow.kind; - - infer::ReborrowUpvar(span, *upvar_id) - } - _ => { - span_bug!( span, "Illegal upvar id: {:?}", upvar_id); - } - } - } - mc::NoteClosureEnv(ref upvar_id) => { - // We don't have any mutability changes to propagate, but - // we do want to note that an upvar reborrow caused this - // link - infer::ReborrowUpvar(span, *upvar_id) - } - _ => { - infer::Reborrow(span) - } - }; - - debug!("link_reborrowed_region: {:?} <= {:?}", - borrow_region, - ref_region); - self.sub_regions(cause, *borrow_region, ref_region); - - // If we end up needing to recurse and establish a region link - // with `ref_cmt`, calculate what borrow kind we will end up - // needing. This will be used below. - // - // One interesting twist is that we can weaken the borrow kind - // when we recurse: to reborrow an `&mut` referent as mutable, - // borrowck requires a unique path to the `&mut` reference but not - // necessarily a *mutable* path. - let new_borrow_kind = match borrow_kind { - ty::ImmBorrow => - ty::ImmBorrow, - ty::MutBorrow | ty::UniqueImmBorrow => - ty::UniqueImmBorrow - }; - - // Decide whether we need to recurse and link any regions within - // the `ref_cmt`. This is concerned for the case where the value - // being reborrowed is in fact a borrowed pointer found within - // another borrowed pointer. For example: - // - // let p: &'b &'a mut T = ...; - // ... - // &'z **p - // - // What makes this case particularly tricky is that, if the data - // being borrowed is a `&mut` or `&uniq` borrow, borrowck requires - // not only that `'z <= 'a`, (as before) but also `'z <= 'b` - // (otherwise the user might mutate through the `&mut T` reference - // after `'b` expires and invalidate the borrow we are looking at - // now). - // - // So let's re-examine our parameters in light of this more - // complicated (possible) scenario: - // - // A borrow of: `& 'z bk * * p` where `p` has type `&'b bk & 'a bk T` - // borrow_region ^~ ref_region ^~ - // borrow_kind ^~ ref_kind ^~ - // ref_cmt ^~~ - // - // (Note that since we have not examined `ref_cmt.cat`, we don't - // know whether this scenario has occurred; but I wanted to show - // how all the types get adjusted.) - match ref_kind { - ty::ImmBorrow => { - // The reference being reborrowed is a sharable ref of - // type `&'a T`. In this case, it doesn't matter where we - // *found* the `&T` pointer, the memory it references will - // be valid and immutable for `'a`. So we can stop here. - // - // (Note that the `borrow_kind` must also be ImmBorrow or - // else the user is borrowed imm memory as mut memory, - // which means they'll get an error downstream in borrowck - // anyhow.) - return None; - } - - ty::MutBorrow | ty::UniqueImmBorrow => { - // The reference being reborrowed is either an `&mut T` or - // `&uniq T`. This is the case where recursion is needed. - return Some((ref_cmt, new_borrow_kind)); - } - } -} - -/// Checks that the values provided for type/region arguments in a given -/// expression are well-formed and in-scope. -fn substs_wf_in_scope(&mut self, - origin: infer::ParameterOrigin, - substs: &Substs<'tcx>, - expr_span: Span, - expr_region: ty::Region) { - debug!("substs_wf_in_scope(substs={:?}, \ - expr_region={:?}, \ - origin={:?}, \ - expr_span={:?})", - substs, expr_region, origin, expr_span); - - let origin = infer::ParameterInScope(origin, expr_span); - - for ®ion in &substs.regions { - self.sub_regions(origin.clone(), expr_region, region); + // Fallback to verifying after the fact that there exists a + // declared bound, or that all the components appearing in the + // projection outlive; in some cases, this may add insufficient + // edges into the inference graph, leading to inference failures + // even though a satisfactory solution exists. + let verify_bound = self.projection_bound(origin.span(), env_bounds, projection_ty); + let generic = GenericKind::Projection(projection_ty); + self.verify_generic_bound(origin, generic.clone(), region, verify_bound); } - for &ty in &substs.types { - let ty = self.resolve_type(ty); - self.type_must_outlive(origin.clone(), ty, expr_region); - } -} - -/// Ensures that type is well-formed in `region`, which implies (among -/// other things) that all borrowed data reachable via `ty` outlives -/// `region`. -pub fn type_must_outlive(&self, - origin: infer::SubregionOrigin<'tcx>, - ty: Ty<'tcx>, - region: ty::Region) -{ - let ty = self.resolve_type(ty); - - debug!("type_must_outlive(ty={:?}, region={:?}, origin={:?})", - ty, - region, - origin); - - assert!(!ty.has_escaping_regions()); - - let components = self.outlives_components(ty); - self.components_must_outlive(origin, components, region); -} - -fn components_must_outlive(&self, - origin: infer::SubregionOrigin<'tcx>, - components: Vec>, - region: ty::Region) -{ - for component in components { - let origin = origin.clone(); - match component { - ty::outlives::Component::Region(region1) => { - self.sub_regions(origin, region, region1); + fn type_bound(&self, span: Span, ty: Ty<'tcx>) -> VerifyBound { + match ty.sty { + ty::TyParam(p) => { + self.param_bound(p) } - ty::outlives::Component::Param(param_ty) => { - self.param_ty_must_outlive(origin, region, param_ty); + ty::TyProjection(data) => { + let declared_bounds = self.projection_declared_bounds(span, data); + self.projection_bound(span, declared_bounds, data) } - ty::outlives::Component::Projection(projection_ty) => { - self.projection_must_outlive(origin, region, projection_ty); - } - ty::outlives::Component::EscapingProjection(subcomponents) => { - self.components_must_outlive(origin, subcomponents, region); - } - ty::outlives::Component::UnresolvedInferenceVariable(v) => { - // ignore this, we presume it will yield an error - // later, since if a type variable is not resolved by - // this point it never will be - self.tcx.sess.delay_span_bug( - origin.span(), - &format!("unresolved inference variable in outlives: {:?}", v)); + _ => { + self.recursive_type_bound(span, ty) } } } -} -fn param_ty_must_outlive(&self, - origin: infer::SubregionOrigin<'tcx>, - region: ty::Region, - param_ty: ty::ParamTy) { - debug!("param_ty_must_outlive(region={:?}, param_ty={:?}, origin={:?})", - region, param_ty, origin); + fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound { + let param_env = &self.parameter_environment; - let verify_bound = self.param_bound(param_ty); - let generic = GenericKind::Param(param_ty); - self.verify_generic_bound(origin, generic, region, verify_bound); -} + debug!("param_bound(param_ty={:?})", + param_ty); -fn projection_must_outlive(&self, - origin: infer::SubregionOrigin<'tcx>, - region: ty::Region, - projection_ty: ty::ProjectionTy<'tcx>) -{ - debug!("projection_must_outlive(region={:?}, projection_ty={:?}, origin={:?})", - region, projection_ty, origin); + let mut param_bounds = self.declared_generic_bounds_from_env(GenericKind::Param(param_ty)); - // This case is thorny for inference. The fundamental problem is - // that there are many cases where we have choice, and inference - // doesn't like choice (the current region inference in - // particular). :) First off, we have to choose between using the - // OutlivesProjectionEnv, OutlivesProjectionTraitDef, and - // OutlivesProjectionComponent rules, any one of which is - // sufficient. If there are no inference variables involved, it's - // not hard to pick the right rule, but if there are, we're in a - // bit of a catch 22: if we picked which rule we were going to - // use, we could add constraints to the region inference graph - // that make it apply, but if we don't add those constraints, the - // rule might not apply (but another rule might). For now, we err - // on the side of adding too few edges into the graph. + // Add in the default bound of fn body that applies to all in + // scope type parameters: + param_bounds.push(param_env.implicit_region_bound); - // Compute the bounds we can derive from the environment or trait - // definition. We know that the projection outlives all the - // regions in this list. - let env_bounds = self.projection_declared_bounds(origin.span(), projection_ty); - - debug!("projection_must_outlive: env_bounds={:?}", - env_bounds); - - // If we know that the projection outlives 'static, then we're - // done here. - if env_bounds.contains(&ty::ReStatic) { - debug!("projection_must_outlive: 'static as declared bound"); - return; + VerifyBound::AnyRegion(param_bounds) } - // If declared bounds list is empty, the only applicable rule is - // OutlivesProjectionComponent. If there are inference variables, - // then, we can break down the outlives into more primitive - // components without adding unnecessary edges. - // - // If there are *no* inference variables, however, we COULD do - // this, but we choose not to, because the error messages are less - // good. For example, a requirement like `T::Item: 'r` would be - // translated to a requirement that `T: 'r`; when this is reported - // to the user, it will thus say "T: 'r must hold so that T::Item: - // 'r holds". But that makes it sound like the only way to fix - // the problem is to add `T: 'r`, which isn't true. So, if there are no - // inference variables, we use a verify constraint instead of adding - // edges, which winds up enforcing the same condition. - let needs_infer = { - projection_ty.trait_ref.substs.types.iter().any(|t| t.needs_infer()) || - projection_ty.trait_ref.substs.regions.iter().any(|r| r.needs_infer()) - }; - if env_bounds.is_empty() && needs_infer { - debug!("projection_must_outlive: no declared bounds"); + fn projection_declared_bounds(&self, + span: Span, + projection_ty: ty::ProjectionTy<'tcx>) + -> Vec + { + // First assemble bounds from where clauses and traits. - for &component_ty in &projection_ty.trait_ref.substs.types { - self.type_must_outlive(origin.clone(), component_ty, region); - } + let mut declared_bounds = + self.declared_generic_bounds_from_env(GenericKind::Projection(projection_ty)); - for &r in &projection_ty.trait_ref.substs.regions { - self.sub_regions(origin.clone(), region, r); - } + declared_bounds.extend_from_slice( + &self.declared_projection_bounds_from_trait(span, projection_ty)); - return; + declared_bounds } - // If we find that there is a unique declared bound `'b`, and this bound - // appears in the trait reference, then the best action is to require that `'b:'r`, - // so do that. This is best no matter what rule we use: - // - // - OutlivesProjectionEnv or OutlivesProjectionTraitDef: these would translate to - // the requirement that `'b:'r` - // - OutlivesProjectionComponent: this would require `'b:'r` in addition to other conditions - if !env_bounds.is_empty() && env_bounds[1..].iter().all(|b| *b == env_bounds[0]) { - let unique_bound = env_bounds[0]; - debug!("projection_must_outlive: unique declared bound = {:?}", unique_bound); - if projection_ty.trait_ref.substs.regions - .iter() - .any(|r| env_bounds.contains(r)) - { - debug!("projection_must_outlive: unique declared bound appears in trait ref"); - self.sub_regions(origin.clone(), region, unique_bound); - return; + fn projection_bound(&self, + span: Span, + declared_bounds: Vec, + projection_ty: ty::ProjectionTy<'tcx>) + -> VerifyBound { + debug!("projection_bound(declared_bounds={:?}, projection_ty={:?})", + declared_bounds, projection_ty); + + // see the extensive comment in projection_must_outlive + + let ty = self.tcx.mk_projection(projection_ty.trait_ref, projection_ty.item_name); + let recursive_bound = self.recursive_type_bound(span, ty); + + VerifyBound::AnyRegion(declared_bounds).or(recursive_bound) + } + + fn recursive_type_bound(&self, span: Span, ty: Ty<'tcx>) -> VerifyBound { + let mut bounds = vec![]; + + for subty in ty.walk_shallow() { + bounds.push(self.type_bound(span, subty)); + } + + let mut regions = ty.regions(); + regions.retain(|r| !r.is_bound()); // ignore late-bound regions + bounds.push(VerifyBound::AllRegions(regions)); + + // remove bounds that must hold, since they are not interesting + bounds.retain(|b| !b.must_hold()); + + if bounds.len() == 1 { + bounds.pop().unwrap() + } else { + VerifyBound::AllBounds(bounds) } } - // Fallback to verifying after the fact that there exists a - // declared bound, or that all the components appearing in the - // projection outlive; in some cases, this may add insufficient - // edges into the inference graph, leading to inference failures - // even though a satisfactory solution exists. - let verify_bound = self.projection_bound(origin.span(), env_bounds, projection_ty); - let generic = GenericKind::Projection(projection_ty); - self.verify_generic_bound(origin, generic.clone(), region, verify_bound); -} + fn declared_generic_bounds_from_env(&self, generic: GenericKind<'tcx>) + -> Vec + { + let param_env = &self.parameter_environment; -fn type_bound(&self, span: Span, ty: Ty<'tcx>) -> VerifyBound { - match ty.sty { - ty::TyParam(p) => { - self.param_bound(p) + // To start, collect bounds from user: + let mut param_bounds = self.tcx.required_region_bounds(generic.to_ty(self.tcx), + param_env.caller_bounds.clone()); + + // Next, collect regions we scraped from the well-formedness + // constraints in the fn signature. To do that, we walk the list + // of known relations from the fn ctxt. + // + // This is crucial because otherwise code like this fails: + // + // fn foo<'a, A>(x: &'a A) { x.bar() } + // + // The problem is that the type of `x` is `&'a A`. To be + // well-formed, then, A must be lower-generic by `'a`, but we + // don't know that this holds from first principles. + for &(r, p) in &self.region_bound_pairs { + debug!("generic={:?} p={:?}", + generic, + p); + if generic == p { + param_bounds.push(r); + } } - ty::TyProjection(data) => { - let declared_bounds = self.projection_declared_bounds(span, data); - self.projection_bound(span, declared_bounds, data) - } - _ => { - self.recursive_type_bound(span, ty) - } - } -} -fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound { - let param_env = &self.parameter_environment; - - debug!("param_bound(param_ty={:?})", - param_ty); - - let mut param_bounds = self.declared_generic_bounds_from_env(GenericKind::Param(param_ty)); - - // Add in the default bound of fn body that applies to all in - // scope type parameters: - param_bounds.push(param_env.implicit_region_bound); - - VerifyBound::AnyRegion(param_bounds) -} - -fn projection_declared_bounds(&self, - span: Span, - projection_ty: ty::ProjectionTy<'tcx>) - -> Vec -{ - // First assemble bounds from where clauses and traits. - - let mut declared_bounds = - self.declared_generic_bounds_from_env(GenericKind::Projection(projection_ty)); - - declared_bounds.extend_from_slice( - &self.declared_projection_bounds_from_trait(span, projection_ty)); - - declared_bounds -} - -fn projection_bound(&self, - span: Span, - declared_bounds: Vec, - projection_ty: ty::ProjectionTy<'tcx>) - -> VerifyBound { - debug!("projection_bound(declared_bounds={:?}, projection_ty={:?})", - declared_bounds, projection_ty); - - // see the extensive comment in projection_must_outlive - - let ty = self.tcx.mk_projection(projection_ty.trait_ref, projection_ty.item_name); - let recursive_bound = self.recursive_type_bound(span, ty); - - VerifyBound::AnyRegion(declared_bounds).or(recursive_bound) -} - -fn recursive_type_bound(&self, span: Span, ty: Ty<'tcx>) -> VerifyBound { - let mut bounds = vec![]; - - for subty in ty.walk_shallow() { - bounds.push(self.type_bound(span, subty)); + param_bounds } - let mut regions = ty.regions(); - regions.retain(|r| !r.is_bound()); // ignore late-bound regions - bounds.push(VerifyBound::AllRegions(regions)); + fn declared_projection_bounds_from_trait(&self, + span: Span, + projection_ty: ty::ProjectionTy<'tcx>) + -> Vec + { + debug!("projection_bounds(projection_ty={:?})", + projection_ty); - // remove bounds that must hold, since they are not interesting - bounds.retain(|b| !b.must_hold()); + let ty = self.tcx.mk_projection(projection_ty.trait_ref.clone(), + projection_ty.item_name); - if bounds.len() == 1 { - bounds.pop().unwrap() - } else { - VerifyBound::AllBounds(bounds) - } -} + // Say we have a projection `>::SomeType`. We are interested + // in looking for a trait definition like: + // + // ``` + // trait SomeTrait<'a> { + // type SomeType : 'a; + // } + // ``` + // + // we can thus deduce that `>::SomeType : 'a`. + let trait_predicates = self.tcx.lookup_predicates(projection_ty.trait_ref.def_id); + let predicates = trait_predicates.predicates.as_slice().to_vec(); + traits::elaborate_predicates(self.tcx, predicates) + .filter_map(|predicate| { + // we're only interesting in `T : 'a` style predicates: + let outlives = match predicate { + ty::Predicate::TypeOutlives(data) => data, + _ => { return None; } + }; -fn declared_generic_bounds_from_env(&self, generic: GenericKind<'tcx>) - -> Vec -{ - let param_env = &self.parameter_environment; - - // To start, collect bounds from user: - let mut param_bounds = self.tcx.required_region_bounds(generic.to_ty(self.tcx), - param_env.caller_bounds.clone()); - - // Next, collect regions we scraped from the well-formedness - // constraints in the fn signature. To do that, we walk the list - // of known relations from the fn ctxt. - // - // This is crucial because otherwise code like this fails: - // - // fn foo<'a, A>(x: &'a A) { x.bar() } - // - // The problem is that the type of `x` is `&'a A`. To be - // well-formed, then, A must be lower-generic by `'a`, but we - // don't know that this holds from first principles. - for &(r, p) in &self.region_bound_pairs { - debug!("generic={:?} p={:?}", - generic, - p); - if generic == p { - param_bounds.push(r); - } - } - - param_bounds -} - -fn declared_projection_bounds_from_trait(&self, - span: Span, - projection_ty: ty::ProjectionTy<'tcx>) - -> Vec -{ - debug!("projection_bounds(projection_ty={:?})", - projection_ty); - - let ty = self.tcx.mk_projection(projection_ty.trait_ref.clone(), - projection_ty.item_name); - - // Say we have a projection `>::SomeType`. We are interested - // in looking for a trait definition like: - // - // ``` - // trait SomeTrait<'a> { - // type SomeType : 'a; - // } - // ``` - // - // we can thus deduce that `>::SomeType : 'a`. - let trait_predicates = self.tcx.lookup_predicates(projection_ty.trait_ref.def_id); - let predicates = trait_predicates.predicates.as_slice().to_vec(); - traits::elaborate_predicates(self.tcx, predicates) - .filter_map(|predicate| { - // we're only interesting in `T : 'a` style predicates: - let outlives = match predicate { - ty::Predicate::TypeOutlives(data) => data, - _ => { return None; } - }; - - debug!("projection_bounds: outlives={:?} (1)", - outlives); - - // apply the substitutions (and normalize any projected types) - let outlives = self.instantiate_type_scheme(span, - projection_ty.trait_ref.substs, - &outlives); - - debug!("projection_bounds: outlives={:?} (2)", - outlives); - - let region_result = self.commit_if_ok(|_| { - let (outlives, _) = - self.replace_late_bound_regions_with_fresh_var( - span, - infer::AssocTypeProjection(projection_ty.item_name), - &outlives); - - debug!("projection_bounds: outlives={:?} (3)", + debug!("projection_bounds: outlives={:?} (1)", outlives); - // check whether this predicate applies to our current projection - match self.eq_types(false, TypeOrigin::Misc(span), ty, outlives.0) { - Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - Ok(outlives.1) + // apply the substitutions (and normalize any projected types) + let outlives = self.instantiate_type_scheme(span, + projection_ty.trait_ref.substs, + &outlives); + + debug!("projection_bounds: outlives={:?} (2)", + outlives); + + let region_result = self.commit_if_ok(|_| { + let (outlives, _) = + self.replace_late_bound_regions_with_fresh_var( + span, + infer::AssocTypeProjection(projection_ty.item_name), + &outlives); + + debug!("projection_bounds: outlives={:?} (3)", + outlives); + + // check whether this predicate applies to our current projection + match self.eq_types(false, TypeOrigin::Misc(span), ty, outlives.0) { + Ok(InferOk { obligations, .. }) => { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()); + Ok(outlives.1) + } + Err(_) => { Err(()) } } - Err(_) => { Err(()) } - } - }); + }); - debug!("projection_bounds: region_result={:?}", - region_result); + debug!("projection_bounds: region_result={:?}", + region_result); - region_result.ok() - }) - .collect() -} + region_result.ok() + }) + .collect() + } } diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 10c16391bf7..19964d736f5 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -57,29 +57,29 @@ use rustc::hir::intravisit::{self, Visitor}; // PUBLIC ENTRY POINTS impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { -pub fn closure_analyze_fn(&self, body: &hir::Block) { - let mut seed = SeedBorrowKind::new(self); - seed.visit_block(body); - let closures_with_inferred_kinds = seed.closures_with_inferred_kinds; + pub fn closure_analyze_fn(&self, body: &hir::Block) { + let mut seed = SeedBorrowKind::new(self); + seed.visit_block(body); + let closures_with_inferred_kinds = seed.closures_with_inferred_kinds; - let mut adjust = AdjustBorrowKind::new(self, &closures_with_inferred_kinds); - adjust.visit_block(body); + let mut adjust = AdjustBorrowKind::new(self, &closures_with_inferred_kinds); + adjust.visit_block(body); - // it's our job to process these. - assert!(self.deferred_call_resolutions.borrow().is_empty()); -} + // it's our job to process these. + assert!(self.deferred_call_resolutions.borrow().is_empty()); + } -pub fn closure_analyze_const(&self, body: &hir::Expr) { - let mut seed = SeedBorrowKind::new(self); - seed.visit_expr(body); - let closures_with_inferred_kinds = seed.closures_with_inferred_kinds; + pub fn closure_analyze_const(&self, body: &hir::Expr) { + let mut seed = SeedBorrowKind::new(self); + seed.visit_expr(body); + let closures_with_inferred_kinds = seed.closures_with_inferred_kinds; - let mut adjust = AdjustBorrowKind::new(self, &closures_with_inferred_kinds); - adjust.visit_expr(body); + let mut adjust = AdjustBorrowKind::new(self, &closures_with_inferred_kinds); + adjust.visit_expr(body); - // it's our job to process these. - assert!(self.deferred_call_resolutions.borrow().is_empty()); -} + // it's our job to process these. + assert!(self.deferred_call_resolutions.borrow().is_empty()); + } } /////////////////////////////////////////////////////////////////////////// @@ -288,7 +288,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { upvar_id); // to move out of an upvar, this must be a FnOnce closure - self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnOnce); + self.adjust_closure_kind(upvar_id.closure_expr_id, + ty::ClosureKind::FnOnce); let upvar_capture_map = &mut self.fcx.tables.borrow_mut().upvar_capture_map; @@ -301,7 +302,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { // must still adjust the kind of the closure // to be a FnOnce closure to permit moves out // of the environment. - self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnOnce); + self.adjust_closure_kind(upvar_id.closure_expr_id, + ty::ClosureKind::FnOnce); } mc::NoteNone => { } @@ -423,9 +425,10 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { } } - /// We infer the borrow_kind with which to borrow upvars in a stack closure. The borrow_kind - /// basically follows a lattice of `imm < unique-imm < mut`, moving from left to right as needed - /// (but never right to left). Here the argument `mutbl` is the borrow_kind that is required by + /// We infer the borrow_kind with which to borrow upvars in a stack closure. + /// The borrow_kind basically follows a lattice of `imm < unique-imm < mut`, + /// moving from left to right as needed (but never right to left). + /// Here the argument `mutbl` is the borrow_kind that is required by /// some particular use. fn adjust_upvar_borrow_kind(&self, upvar_id: ty::UpvarId, diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index bb63cf11d9a..e0a34189773 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -576,46 +576,46 @@ struct AdtField<'tcx> { } impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { -fn struct_variant(&self, struct_def: &hir::VariantData) -> AdtVariant<'tcx> { - let fields = - struct_def.fields().iter() - .map(|field| { - let field_ty = self.tcx.node_id_to_type(field.id); - let field_ty = self.instantiate_type_scheme(field.span, - &self.parameter_environment - .free_substs, - &field_ty); - AdtField { ty: field_ty, span: field.span } - }) - .collect(); - AdtVariant { fields: fields } -} + fn struct_variant(&self, struct_def: &hir::VariantData) -> AdtVariant<'tcx> { + let fields = + struct_def.fields().iter() + .map(|field| { + let field_ty = self.tcx.node_id_to_type(field.id); + let field_ty = self.instantiate_type_scheme(field.span, + &self.parameter_environment + .free_substs, + &field_ty); + AdtField { ty: field_ty, span: field.span } + }) + .collect(); + AdtVariant { fields: fields } + } -fn enum_variants(&self, enum_def: &hir::EnumDef) -> Vec> { - enum_def.variants.iter() - .map(|variant| self.struct_variant(&variant.node.data)) - .collect() -} + fn enum_variants(&self, enum_def: &hir::EnumDef) -> Vec> { + enum_def.variants.iter() + .map(|variant| self.struct_variant(&variant.node.data)) + .collect() + } -fn impl_implied_bounds(&self, impl_def_id: DefId, span: Span) -> Vec> { - let free_substs = &self.parameter_environment.free_substs; - match self.tcx.impl_trait_ref(impl_def_id) { - Some(ref trait_ref) => { - // Trait impl: take implied bounds from all types that - // appear in the trait reference. - let trait_ref = self.instantiate_type_scheme(span, free_substs, trait_ref); - trait_ref.substs.types.as_slice().to_vec() - } + fn impl_implied_bounds(&self, impl_def_id: DefId, span: Span) -> Vec> { + let free_substs = &self.parameter_environment.free_substs; + match self.tcx.impl_trait_ref(impl_def_id) { + Some(ref trait_ref) => { + // Trait impl: take implied bounds from all types that + // appear in the trait reference. + let trait_ref = self.instantiate_type_scheme(span, free_substs, trait_ref); + trait_ref.substs.types.as_slice().to_vec() + } - None => { - // Inherent impl: take implied bounds from the self type. - let self_ty = self.tcx.lookup_item_type(impl_def_id).ty; - let self_ty = self.instantiate_type_scheme(span, free_substs, &self_ty); - vec![self_ty] + None => { + // Inherent impl: take implied bounds from the self type. + let self_ty = self.tcx.lookup_item_type(impl_def_id).ty; + let self_ty = self.instantiate_type_scheme(span, free_substs, &self_ty); + vec![self_ty] + } } } } -} fn error_192(ccx: &CrateCtxt, span: Span) { span_err!(ccx.tcx.sess, span, E0192, diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 1c7496d611e..e6500747c05 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -35,35 +35,35 @@ use rustc::hir; // Entry point functions impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { -pub fn resolve_type_vars_in_expr(&self, e: &hir::Expr) { - assert_eq!(self.writeback_errors.get(), false); - let mut wbcx = WritebackCx::new(self); - wbcx.visit_expr(e); - wbcx.visit_upvar_borrow_map(); - wbcx.visit_closures(); - wbcx.visit_liberated_fn_sigs(); - wbcx.visit_fru_field_types(); -} - -pub fn resolve_type_vars_in_fn(&self, decl: &hir::FnDecl, blk: &hir::Block) { - assert_eq!(self.writeback_errors.get(), false); - let mut wbcx = WritebackCx::new(self); - wbcx.visit_block(blk); - for arg in &decl.inputs { - wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.id); - wbcx.visit_pat(&arg.pat); - - // Privacy needs the type for the whole pattern, not just each binding - if !pat_util::pat_is_binding(&self.tcx.def_map.borrow(), &arg.pat) { - wbcx.visit_node_id(ResolvingPattern(arg.pat.span), - arg.pat.id); - } + pub fn resolve_type_vars_in_expr(&self, e: &hir::Expr) { + assert_eq!(self.writeback_errors.get(), false); + let mut wbcx = WritebackCx::new(self); + wbcx.visit_expr(e); + wbcx.visit_upvar_borrow_map(); + wbcx.visit_closures(); + wbcx.visit_liberated_fn_sigs(); + wbcx.visit_fru_field_types(); + } + + pub fn resolve_type_vars_in_fn(&self, decl: &hir::FnDecl, blk: &hir::Block) { + assert_eq!(self.writeback_errors.get(), false); + let mut wbcx = WritebackCx::new(self); + wbcx.visit_block(blk); + for arg in &decl.inputs { + wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.id); + wbcx.visit_pat(&arg.pat); + + // Privacy needs the type for the whole pattern, not just each binding + if !pat_util::pat_is_binding(&self.tcx.def_map.borrow(), &arg.pat) { + wbcx.visit_node_id(ResolvingPattern(arg.pat.span), + arg.pat.id); + } + } + wbcx.visit_upvar_borrow_map(); + wbcx.visit_closures(); + wbcx.visit_liberated_fn_sigs(); + wbcx.visit_fru_field_types(); } - wbcx.visit_upvar_borrow_map(); - wbcx.visit_closures(); - wbcx.visit_liberated_fn_sigs(); - wbcx.visit_fru_field_types(); -} } /////////////////////////////////////////////////////////////////////////// diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 33238f6cda7..8bee0467f11 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -66,39 +66,39 @@ impl<'a, 'gcx, 'tcx, 'v> intravisit::Visitor<'v> for CoherenceCheckVisitor<'a, ' impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { -// Returns the def ID of the base type, if there is one. -fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option { - match ty.sty { - TyEnum(def, _) | - TyStruct(def, _) => { - Some(def.did) - } + // Returns the def ID of the base type, if there is one. + fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option { + match ty.sty { + TyEnum(def, _) | + TyStruct(def, _) => { + Some(def.did) + } - TyTrait(ref t) => { - Some(t.principal_def_id()) - } + TyTrait(ref t) => { + Some(t.principal_def_id()) + } - TyBox(_) => { - self.inference_context.tcx.lang_items.owned_box() - } + TyBox(_) => { + self.inference_context.tcx.lang_items.owned_box() + } - TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | - TyStr | TyArray(..) | TySlice(..) | TyFnDef(..) | TyFnPtr(_) | - TyTuple(..) | TyParam(..) | TyError | - TyRawPtr(_) | TyRef(_, _) | TyProjection(..) => { - None - } + TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | + TyStr | TyArray(..) | TySlice(..) | TyFnDef(..) | TyFnPtr(_) | + TyTuple(..) | TyParam(..) | TyError | + TyRawPtr(_) | TyRef(_, _) | TyProjection(..) => { + None + } - TyInfer(..) | TyClosure(..) => { - // `ty` comes from a user declaration so we should only expect types - // that the user can type - span_bug!( - span, - "coherence encountered unexpected type searching for base type: {}", - ty); + TyInfer(..) | TyClosure(..) => { + // `ty` comes from a user declaration so we should only expect types + // that the user can type + span_bug!( + span, + "coherence encountered unexpected type searching for base type: {}", + ty); + } } } -} fn check(&self) { // Check implementations and traits. This populates the tables