From 0ddf060b6d347f89afb584501c86a4fa96ec7acc Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Tue, 9 Aug 2016 20:57:41 +0800 Subject: [PATCH 01/20] Make write_ty and friends return adjusted type --- src/librustc_typeck/check/_match.rs | 4 +- src/librustc_typeck/check/callee.rs | 23 +-- src/librustc_typeck/check/closure.rs | 8 +- src/librustc_typeck/check/mod.rs | 241 ++++++++++++++------------- src/librustc_typeck/check/op.rs | 23 +-- 5 files changed, 153 insertions(+), 146 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 12fce4b928e08..1f0faab8f2c4a 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -371,7 +371,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { discrim: &'gcx hir::Expr, arms: &'gcx [hir::Arm], expected: Expectation<'tcx>, - match_src: hir::MatchSource) { + match_src: hir::MatchSource) -> Ty<'tcx> { let tcx = self.tcx; // Not entirely obvious: if matches may create ref bindings, we @@ -480,7 +480,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; } - self.write_ty(expr.id, result_ty); + self.write_ty(expr.id, result_ty) } } diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 49db56d2dabd9..4f673606de52f 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -45,7 +45,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { call_expr: &'gcx hir::Expr, callee_expr: &'gcx hir::Expr, arg_exprs: &'gcx [P], - expected: Expectation<'tcx>) + expected: Expectation<'tcx>) -> Ty<'tcx> { self.check_expr(callee_expr); let original_callee_ty = self.expr_ty(callee_expr); @@ -60,20 +60,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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); + 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); + 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.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); + arg_exprs, expected, method_callee) } } } @@ -181,7 +181,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { call_expr: &hir::Expr, callee_ty: Ty<'tcx>, arg_exprs: &'gcx [P], - expected: Expectation<'tcx>) + expected: Expectation<'tcx>) -> Ty<'tcx> { let error_fn_sig; @@ -245,14 +245,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn_sig.variadic, TupleArgumentsFlag::DontTupleArguments); - self.write_call(call_expr, fn_sig.output); + self.write_ty(call_expr.id, 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: ty::FnSig<'tcx>) -> Ty<'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 @@ -272,7 +272,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn_sig.variadic, TupleArgumentsFlag::TupleArguments); - self.write_call(call_expr, fn_sig.output); + self.write_ty(call_expr.id, fn_sig.output) } fn confirm_overloaded_call(&self, @@ -280,7 +280,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { callee_expr: &'gcx hir::Expr, arg_exprs: &'gcx [P], expected: Expectation<'tcx>, - method_callee: ty::MethodCallee<'tcx>) + method_callee: ty::MethodCallee<'tcx>) -> Ty<'tcx> { let output_type = self.check_method_argument_types(call_expr.span, @@ -289,9 +289,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { arg_exprs, TupleArgumentsFlag::TupleArguments, expected); - self.write_call(call_expr, output_type); + let ty = self.write_ty(call_expr.id, output_type); self.write_overloaded_call_method_map(call_expr, method_callee); + ty } fn write_overloaded_call_method_map(&self, diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 8980cb9076027..1f4201aa39cdd 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -24,7 +24,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _capture: hir::CaptureClause, decl: &'gcx hir::FnDecl, body: &'gcx hir::Block, - expected: Expectation<'tcx>) { + expected: Expectation<'tcx>) -> Ty<'tcx> { debug!("check_expr_closure(expr={:?},expected={:?})", expr, expected); @@ -44,7 +44,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { opt_kind: Option, decl: &'gcx hir::FnDecl, body: &'gcx hir::Block, - expected_sig: Option>) { + expected_sig: Option>) -> Ty<'tcx> { let expr_def_id = self.tcx.map.local_def_id(expr.id); debug!("check_closure opt_kind={:?} expected_sig={:?}", @@ -70,7 +70,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.parameter_environment.free_substs, upvar_tys); - self.write_ty(expr.id, closure_type); + let ty = 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); @@ -93,6 +93,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Some(kind) => { self.tables.borrow_mut().closure_kinds.insert(expr_def_id, kind); } None => { } } + + ty } fn deduce_expectations_from_expected_type(&self, expected_ty: Ty<'tcx>) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 0aa523e9d5e47..5c528cc46a73c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1530,7 +1530,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } #[inline] - pub fn write_ty(&self, node_id: ast::NodeId, ty: Ty<'tcx>) { + pub fn write_ty(&self, node_id: ast::NodeId, ty: Ty<'tcx>) -> Ty<'tcx> { debug!("write_ty({}, {:?}) in fcx {}", node_id, ty, self.tag()); self.tables.borrow_mut().node_types.insert(node_id, ty); @@ -1538,10 +1538,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Add adjustments to !-expressions if ty.is_never() { if let Some(hir::map::NodeExpr(_)) = self.tcx.map.find(node_id) { - let adj = adjustment::AdjustNeverToAny(self.next_diverging_ty_var()); + let adj_ty = self.next_diverging_ty_var(); + let adj = adjustment::AdjustNeverToAny(adj_ty); self.write_adjustment(node_id, adj); + return adj_ty; } } + ty } pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) { @@ -1715,16 +1718,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty_substituted } - pub fn write_nil(&self, node_id: ast::NodeId) { - self.write_ty(node_id, self.tcx.mk_nil()); + pub fn write_nil(&self, node_id: ast::NodeId) -> Ty<'tcx> { + self.write_ty(node_id, self.tcx.mk_nil()) } - pub fn write_never(&self, node_id: ast::NodeId) { - self.write_ty(node_id, self.tcx.types.never); + pub fn write_never(&self, node_id: ast::NodeId) -> Ty<'tcx> { + self.write_ty(node_id, self.tcx.types.never) } - pub fn write_error(&self, node_id: ast::NodeId) { - self.write_ty(node_id, self.tcx.types.err); + pub fn write_error(&self, node_id: ast::NodeId) -> Ty<'tcx> { + self.write_ty(node_id, self.tcx.types.err) } pub fn require_type_meets(&self, @@ -2666,12 +2669,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { (0..len).map(|_| self.tcx.types.err).collect() } - fn write_call(&self, - call_expr: &hir::Expr, - output: Ty<'tcx>) { - self.write_ty(call_expr.id, output); - } - // AST fragment checking fn check_lit(&self, lit: &ast::Lit, @@ -2727,35 +2724,37 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn check_expr_has_type(&self, expr: &'gcx hir::Expr, - expected: Ty<'tcx>) { - self.check_expr_with_hint(expr, expected); + expected: Ty<'tcx>) -> Ty<'tcx> { + let ty = self.check_expr_with_hint(expr, expected); self.demand_suptype(expr.span, expected, self.expr_ty(expr)); + ty } fn check_expr_coercable_to_type(&self, expr: &'gcx hir::Expr, - expected: Ty<'tcx>) { - self.check_expr_with_hint(expr, expected); + expected: Ty<'tcx>) -> Ty<'tcx> { + let ty = self.check_expr_with_hint(expr, expected); self.demand_coerce(expr, expected); + ty } fn check_expr_with_hint(&self, expr: &'gcx hir::Expr, - expected: Ty<'tcx>) { + expected: Ty<'tcx>) -> Ty<'tcx> { self.check_expr_with_expectation(expr, ExpectHasType(expected)) } fn check_expr_with_expectation(&self, expr: &'gcx hir::Expr, - expected: Expectation<'tcx>) { + expected: Expectation<'tcx>) -> Ty<'tcx> { self.check_expr_with_expectation_and_lvalue_pref(expr, expected, NoPreference) } - fn check_expr(&self, expr: &'gcx hir::Expr) { + fn check_expr(&self, expr: &'gcx hir::Expr) -> Ty<'tcx> { self.check_expr_with_expectation(expr, NoExpectation) } fn check_expr_with_lvalue_pref(&self, expr: &'gcx hir::Expr, - lvalue_pref: LvaluePreference) { + lvalue_pref: LvaluePreference) -> Ty<'tcx> { self.check_expr_with_expectation_and_lvalue_pref(expr, NoExpectation, lvalue_pref) } @@ -2820,7 +2819,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { args: &'gcx [P], tps: &[P], expected: Expectation<'tcx>, - lvalue_pref: LvaluePreference) { + lvalue_pref: LvaluePreference) -> Ty<'tcx> { let rcvr = &args[0]; self.check_expr_with_lvalue_pref(&rcvr, lvalue_pref); @@ -2856,7 +2855,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { DontTupleArguments, expected); - self.write_call(expr, ret_ty); + self.write_ty(expr.id, ret_ty) } // A generic function for checking the then and else in an if @@ -2867,7 +2866,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { opt_else_expr: Option<&'gcx hir::Expr>, id: ast::NodeId, sp: Span, - expected: Expectation<'tcx>) { + expected: Expectation<'tcx>) -> Ty<'tcx> { self.check_expr_has_type(cond_expr, self.tcx.types.bool); let expected = expected.adjust_for_branches(self); @@ -2932,7 +2931,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; - self.write_ty(id, if_ty); + self.write_ty(id, if_ty) } // Check field access expressions @@ -2940,7 +2939,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr: &'gcx hir::Expr, lvalue_pref: LvaluePreference, base: &'gcx hir::Expr, - field: &Spanned) { + field: &Spanned) -> Ty<'tcx> { self.check_expr_with_lvalue_pref(base, lvalue_pref); let expr_t = self.structurally_resolved_type(expr.span, self.expr_ty(base)); @@ -2954,9 +2953,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let field_ty = self.field_ty(expr.span, field, substs); if field.vis.is_accessible_from(self.body_id, &self.tcx().map) { autoderef.finalize(lvalue_pref, Some(base)); - self.write_ty(expr.id, field_ty); + let ty = self.write_ty(expr.id, field_ty); self.write_autoderef_adjustment(base.id, autoderefs); - return; + return ty; } private_candidate = Some((base_def.did, field_ty)); } @@ -2968,7 +2967,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some((did, field_ty)) = private_candidate { let struct_path = self.tcx().item_path_str(did); - self.write_ty(expr.id, field_ty); + let ty = self.write_ty(expr.id, field_ty); let msg = format!("field `{}` of struct `{}` is private", field.node, struct_path); let mut err = self.tcx().sess.struct_span_err(expr.span, &msg); // Also check if an accessible method exists, which is often what is meant. @@ -2977,8 +2976,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { field.node)); } err.emit(); + ty } else if field.node == keywords::Invalid.name() { - self.write_error(expr.id); + self.write_error(expr.id) } else if self.method_exists(field.span, field.node, expr_t, expr.id, true) { self.type_error_struct(field.span, |actual| { format!("attempted to take value of method `{}` on type \ @@ -2987,7 +2987,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .help("maybe a `()` to call it is missing? \ If not, try an anonymous function") .emit(); - self.write_error(expr.id); + self.write_error(expr.id) } else { let mut err = self.type_error_struct(expr.span, |actual| { format!("attempted access of field `{}` on type `{}`, \ @@ -3005,7 +3005,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => {} } err.emit(); - self.write_error(expr.id); + self.write_error(expr.id) } } @@ -3037,7 +3037,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr: &'gcx hir::Expr, lvalue_pref: LvaluePreference, base: &'gcx hir::Expr, - idx: codemap::Spanned) { + idx: codemap::Spanned) -> Ty<'tcx> { self.check_expr_with_lvalue_pref(base, lvalue_pref); let expr_t = self.structurally_resolved_type(expr.span, self.expr_ty(base)); @@ -3070,9 +3070,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(field_ty) = field { autoderef.finalize(lvalue_pref, Some(base)); - self.write_ty(expr.id, field_ty); + let ty = self.write_ty(expr.id, field_ty); self.write_autoderef_adjustment(base.id, autoderefs); - return; + return ty; } } autoderef.unambiguous_final_ty(); @@ -3081,8 +3081,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let struct_path = self.tcx().item_path_str(did); let msg = format!("field `{}` of struct `{}` is private", idx.node, struct_path); self.tcx().sess.span_err(expr.span, &msg); - self.write_ty(expr.id, field_ty); - return; + return self.write_ty(expr.id, field_ty) } self.type_error_message( @@ -3102,7 +3101,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }, expr_t); - self.write_error(expr.id); + self.write_error(expr.id) } fn report_unknown_field(&self, @@ -3207,17 +3206,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn check_struct_fields_on_error(&self, id: ast::NodeId, fields: &'gcx [hir::Field], - base_expr: &'gcx Option>) { + base_expr: &'gcx Option>) -> Ty<'tcx> { // Make sure to still write the types // otherwise we might ICE - self.write_error(id); + let ty = self.write_error(id); for field in fields { self.check_expr(&field.expr); } match *base_expr { - Some(ref base) => self.check_expr(&base), + Some(ref base) => { + self.check_expr(&base); + }, None => {} } + ty } pub fn check_struct_path(&self, @@ -3267,15 +3269,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr: &hir::Expr, path: &hir::Path, fields: &'gcx [hir::Field], - base_expr: &'gcx Option>) + base_expr: &'gcx Option>) -> Ty<'tcx> { // Find the relevant variant let (variant, expr_ty) = if let Some(variant_ty) = self.check_struct_path(path, expr.id, expr.span) { variant_ty } else { - self.check_struct_fields_on_error(expr.id, fields, base_expr); - return; + return self.check_struct_fields_on_error(expr.id, fields, base_expr); }; self.check_expr_struct_fields(expr_ty, path.span, variant, fields, @@ -3299,6 +3300,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } } + expr_ty } @@ -3315,13 +3317,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn check_expr_with_expectation_and_lvalue_pref(&self, expr: &'gcx hir::Expr, expected: Expectation<'tcx>, - lvalue_pref: LvaluePreference) { + lvalue_pref: LvaluePreference) -> Ty<'tcx> { debug!(">> typechecking: expr={:?} expected={:?}", expr, expected); let tcx = self.tcx; let id = expr.id; - match expr.node { + let ty = match expr.node { hir::ExprBox(ref subexpr) => { let expected_inner = expected.to_option(self).map_or(NoExpectation, |ty| { match ty.sty { @@ -3331,18 +3333,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }); self.check_expr_with_expectation(subexpr, expected_inner); let referent_ty = self.expr_ty(&subexpr); - self.write_ty(id, tcx.mk_box(referent_ty)); + 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); + self.write_ty(id, typ) } hir::ExprBinary(op, ref lhs, ref rhs) => { - self.check_binop(expr, op, lhs, rhs); + self.check_binop(expr, op, lhs, rhs) } hir::ExprAssignOp(op, ref lhs, ref rhs) => { - self.check_binop_assign(expr, op, lhs, rhs); + self.check_binop_assign(expr, op, lhs, rhs) } hir::ExprUnary(unop, ref oprnd) => { let expected_inner = match unop { @@ -3357,10 +3359,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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); + let mut oprnd_t = self.check_expr_with_expectation_and_lvalue_pref(&oprnd, + expected_inner, + lvalue_pref); if !oprnd_t.references_error() { match unop { @@ -3402,7 +3403,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } } - self.write_ty(id, oprnd_t); + self.write_ty(id, oprnd_t) } hir::ExprAddrOf(mutbl, ref oprnd) => { let hint = expected.only_has_type(self).map_or(NoExpectation, |ty| { @@ -3421,9 +3422,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }); let lvalue_pref = LvaluePreference::from_mutbl(mutbl); - self.check_expr_with_expectation_and_lvalue_pref(&oprnd, hint, lvalue_pref); + let ty = self.check_expr_with_expectation_and_lvalue_pref(&oprnd, hint, lvalue_pref); - let tm = ty::TypeAndMut { ty: self.expr_ty(&oprnd), mutbl: mutbl }; + let tm = ty::TypeAndMut { ty: ty, mutbl: mutbl }; let oprnd_t = if tm.ty.references_error() { tcx.types.err } else { @@ -3443,24 +3444,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let region = self.next_region_var(infer::AddrOfRegion(expr.span)); tcx.mk_ref(region, tm) }; - self.write_ty(id, oprnd_t); + self.write_ty(id, oprnd_t) } hir::ExprPath(ref opt_qself, ref path) => { let opt_self_ty = opt_qself.as_ref().map(|qself| self.to_ty(&qself.ty)); let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(opt_self_ty, path, expr.id, expr.span); - if def != Def::Err { - self.instantiate_value_path(segments, opt_ty, def, expr.span, id); + let ty = if def != Def::Err { + self.instantiate_value_path(segments, opt_ty, def, expr.span, id) } else { self.set_tainted_by_errors(); - self.write_error(id); - } + self.write_error(id) + }; // 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); }); + ty } hir::ExprInlineAsm(_, ref outputs, ref inputs) => { for output in outputs { @@ -3469,10 +3471,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { for input in inputs { self.check_expr(input); } - self.write_nil(id); + self.write_nil(id) } - hir::ExprBreak(_) => { self.write_never(id); } - hir::ExprAgain(_) => { self.write_never(id); } + hir::ExprBreak(_) => { self.write_never(id) } + hir::ExprAgain(_) => { self.write_never(id) } hir::ExprRet(ref expr_opt) => { if let Some(ref e) = *expr_opt { self.check_expr_coercable_to_type(&e, self.ret_ty); @@ -3490,10 +3492,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .emit(); } } - self.write_never(id); + self.write_never(id) } hir::ExprAssign(ref lhs, ref rhs) => { - self.check_expr_with_lvalue_pref(&lhs, PreferMutLvalue); + let lhs_ty = self.check_expr_with_lvalue_pref(&lhs, PreferMutLvalue); let tcx = self.tcx; if !tcx.expr_is_lval(&lhs) { @@ -3506,21 +3508,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .emit(); } - let lhs_ty = self.expr_ty(&lhs); - self.check_expr_coercable_to_type(&rhs, lhs_ty); - let rhs_ty = self.expr_ty(&rhs); + let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty); self.require_expr_have_sized_type(&lhs, traits::AssignmentLhsSized); if lhs_ty.references_error() || rhs_ty.references_error() { - self.write_error(id); + self.write_error(id) } else { - self.write_nil(id); + 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); + id, expr.span, expected) } hir::ExprWhile(ref cond, ref body, _) => { self.check_expr_has_type(&cond, tcx.types.bool); @@ -3528,43 +3528,47 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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); + self.write_error(id) } else { - self.write_nil(id); + self.write_nil(id) } } hir::ExprLoop(ref body, _) => { self.check_block_no_value(&body); if !may_break(tcx, expr.id, &body) { - self.write_never(id); + self.write_never(id) } else { - self.write_nil(id); + self.write_nil(id) } } hir::ExprMatch(ref discrim, ref arms, match_src) => { - self.check_match(expr, &discrim, arms, expected, 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); + 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)); + let ty = self.node_ty(b.id); + self.write_ty(id, ty) } hir::ExprCall(ref callee, ref args) => { - self.check_call(expr, &callee, &args[..], expected); + let ret_ty = 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); + ret_ty } hir::ExprMethodCall(name, ref tps, ref args) => { - self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref); + let ty = 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); + self.write_error(id) + } + else { + ty } } hir::ExprCast(ref e, ref t) => { @@ -3576,26 +3580,26 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // 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_expr = self.check_expr_with_expectation(e, ExpectCastableToType(t_cast)); 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); + 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); + let ty = 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); + ty } Err(ErrorReported) => { - self.write_error(id); + self.write_error(id) } } } @@ -3603,7 +3607,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::ExprType(ref e, ref t) => { let typ = self.to_ty(&t); self.check_expr_eq_type(&e, typ); - self.write_ty(id, typ); + self.write_ty(id, typ) } hir::ExprVec(ref args) => { let uty = expected.to_option(self).and_then(|uty| { @@ -3617,8 +3621,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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 e_ty = self.check_expr_with_hint(e, coerce_to); let origin = TypeOrigin::Misc(e.span); // Special-case the first element, as it has no "previous expressions". @@ -3636,7 +3639,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } } - self.write_ty(id, tcx.mk_array(unified, args.len())); + 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); @@ -3660,8 +3663,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } None => { let t: Ty = self.next_ty_var(); - self.check_expr_has_type(&element, t); - (self.expr_ty(&element), t) + let element_ty = self.check_expr_has_type(&element, t); + (element_ty, t) } }; @@ -3672,10 +3675,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } if element_ty.references_error() { - self.write_error(id); + self.write_error(id) } else { let t = tcx.mk_array(t, count); - self.write_ty(id, t); + self.write_ty(id, t) } } hir::ExprTup(ref elts) => { @@ -3695,49 +3698,46 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ety } _ => { - self.check_expr_with_expectation(&e, NoExpectation); - self.expr_ty(&e) + self.check_expr_with_expectation(&e, NoExpectation) } }; err_field = err_field || t.references_error(); t }).collect(); if err_field { - self.write_error(id); + self.write_error(id) } else { let typ = tcx.mk_tup(elt_ts); - self.write_ty(id, typ); + self.write_ty(id, typ) } } hir::ExprStruct(ref path, ref fields, ref base_expr) => { - self.check_expr_struct(expr, path, fields, base_expr); + let ty = self.check_expr_struct(expr, path, fields, base_expr); self.require_expr_have_sized_type(expr, traits::StructInitializerSized); + ty } hir::ExprField(ref base, ref field) => { - self.check_field(expr, lvalue_pref, &base, field); + self.check_field(expr, lvalue_pref, &base, field) } hir::ExprTupField(ref base, idx) => { - self.check_tup_field(expr, lvalue_pref, &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); + let base_t = self.check_expr_with_lvalue_pref(&base, lvalue_pref); + let idx_t = self.check_expr(&idx); if base_t.references_error() { - self.write_ty(id, base_t); + self.write_ty(id, base_t) } else if idx_t.references_error() { - self.write_ty(id, idx_t); + 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); + self.write_ty(id, element_ty) } None => { self.check_expr_has_type(&idx, self.tcx.types.err); @@ -3773,18 +3773,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } err.emit(); - self.write_ty(id, self.tcx().types.err); + 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), + ty, expected); + ty } // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary. @@ -3878,9 +3879,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // 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); + let init_ty = self.check_expr_with_lvalue_pref(init, LvaluePreference::from_mutbl(m)); self.demand_eqtype(init.span, init_ty, local_ty); + init_ty } else { self.check_expr_coercable_to_type(init, local_ty) }; @@ -3905,7 +3906,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - pub fn check_stmt(&self, stmt: &'gcx hir::Stmt) { + pub fn check_stmt(&self, stmt: &'gcx hir::Stmt) { let node_id; let mut saw_bot = false; let mut saw_err = false; @@ -3945,7 +3946,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.write_error(node_id); } else { - self.write_nil(node_id) + self.write_nil(node_id); } } diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index a8b1683f6d354..feb3258c88c25 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -23,7 +23,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr: &'gcx hir::Expr, op: hir::BinOp, lhs_expr: &'gcx hir::Expr, - rhs_expr: &'gcx hir::Expr) + rhs_expr: &'gcx hir::Expr) -> Ty<'tcx> { self.check_expr_with_lvalue_pref(lhs_expr, PreferMutLvalue); @@ -32,12 +32,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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) { + let 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); + self.tcx.mk_nil() } else { - self.write_ty(expr.id, return_ty); - } + return_ty + }; + let ty = self.write_ty(expr.id, ty); let tcx = self.tcx; if !tcx.expr_is_lval(lhs_expr) { @@ -49,6 +50,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { &format!("invalid expression for left-hand side")) .emit(); } + ty } /// Check a potentially overloaded binary operator. @@ -56,7 +58,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr: &'gcx hir::Expr, op: hir::BinOp, lhs_expr: &'gcx hir::Expr, - rhs_expr: &'gcx hir::Expr) + rhs_expr: &'gcx hir::Expr) -> Ty<'tcx> { let tcx = self.tcx; @@ -70,12 +72,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_expr(lhs_expr); let lhs_ty = self.resolve_type_vars_with_obligations(self.expr_ty(lhs_expr)); - match BinOpCategory::from(op) { + let ty = 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()); + tcx.mk_bool() } _ => { // Otherwise, we always treat operators as if they are @@ -107,9 +109,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.demand_suptype(expr.span, builtin_return_ty, return_ty); } - self.write_ty(expr.id, return_ty); + return_ty } - } + }; + self.write_ty(expr.id, ty) } fn enforce_builtin_binop_types(&self, From b93435fd79e26e09b8aa786eb682c82ec81f0293 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Wed, 10 Aug 2016 00:13:20 +0800 Subject: [PATCH 02/20] Remove most uses of expr_ty --- src/librustc_typeck/check/_match.rs | 20 +++---- src/librustc_typeck/check/callee.rs | 3 +- src/librustc_typeck/check/mod.rs | 85 ++++++++++++----------------- src/librustc_typeck/check/op.rs | 8 +-- 4 files changed, 47 insertions(+), 69 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 1f0faab8f2c4a..2bb0abfab4ee7 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -37,12 +37,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.write_ty(pat.id, expected); } PatKind::Lit(ref lt) => { - self.check_expr(<); - let expr_ty = self.expr_ty(<); + let expr_t = self.check_expr(<); // 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; + let mut pat_ty = expr_t; 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); @@ -63,7 +62,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // 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 + // subtyping is irrelevant, and for strings `expr_t` is // type is `&'static str`, so if we say that // // &'static str <: expected @@ -72,11 +71,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.demand_suptype(pat.span, expected, pat_ty); } PatKind::Range(ref begin, ref end) => { - self.check_expr(begin); - self.check_expr(end); - - let lhs_ty = self.expr_ty(begin); - let rhs_ty = self.expr_ty(end); + let lhs_ty = self.check_expr(begin); + let rhs_ty = 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(); @@ -385,8 +381,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }); 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); + discrim_ty = self.check_expr_with_lvalue_pref(discrim, LvaluePreference::from_mutbl(m)); } else { // ...but otherwise we want to use any supertype of the // discriminant. This is sort of a workaround, see note (*) in @@ -429,8 +424,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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); + let arm_ty = self.check_expr_with_expectation(&arm.body, expected); if result_ty.references_error() || arm_ty.references_error() { result_ty = tcx.types.err; diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 4f673606de52f..bc3c5aba7100b 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -47,8 +47,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { arg_exprs: &'gcx [P], expected: Expectation<'tcx>) -> Ty<'tcx> { - self.check_expr(callee_expr); - let original_callee_ty = self.expr_ty(callee_expr); + let original_callee_ty = self.check_expr(callee_expr); let mut autoderef = self.autoderef(callee_expr.span, original_callee_ty); let result = autoderef.by_ref().flat_map(|(adj_ty, idx)| { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 5c528cc46a73c..774969daf388a 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1750,13 +1750,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.require_type_meets(ty, span, code, ty::BoundSized); } - pub fn require_expr_have_sized_type(&self, - expr: &hir::Expr, - code: traits::ObligationCauseCode<'tcx>) - { - self.require_type_is_sized(self.expr_ty(expr), expr.span, code); - } - pub fn register_builtin_bound(&self, ty: Ty<'tcx>, builtin_bound: ty::BuiltinBound, @@ -1801,7 +1794,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { adjustment: Option<&adjustment::AutoAdjustment<'tcx>>) -> Ty<'tcx> { - let raw_ty = self.expr_ty(expr); + let raw_ty = self.node_ty(expr.id); let raw_ty = self.shallow_resolve(raw_ty); let resolve_ty = |ty: Ty<'tcx>| self.resolve_type_vars_if_possible(&ty); raw_ty.adjust(self.tcx, expr.span, expr.id, adjustment, |method_call| { @@ -2623,12 +2616,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // arguments which we skipped above. if variadic { for arg in args.iter().skip(expected_arg_count) { - self.check_expr(&arg); + let arg_ty = 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)); + arg_ty); match arg_ty.sty { ty::TyFloat(ast::FloatTy::F32) => { self.type_error_message(arg.span, |t| { @@ -2718,15 +2711,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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)); + let ty = self.check_expr_with_hint(expr, expected); + self.demand_eqtype(expr.span, expected, ty); } pub fn check_expr_has_type(&self, expr: &'gcx hir::Expr, expected: Ty<'tcx>) -> Ty<'tcx> { let ty = self.check_expr_with_hint(expr, expected); - self.demand_suptype(expr.span, expected, self.expr_ty(expr)); + self.demand_suptype(expr.span, expected, ty); ty } @@ -2821,10 +2814,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expected: Expectation<'tcx>, lvalue_pref: LvaluePreference) -> Ty<'tcx> { let rcvr = &args[0]; - self.check_expr_with_lvalue_pref(&rcvr, lvalue_pref); + let rcvr_t = self.check_expr_with_lvalue_pref(&rcvr, lvalue_pref); // no need to check for bot/err -- callee does that - let expr_t = self.structurally_resolved_type(expr.span, self.expr_ty(&rcvr)); + let expr_t = self.structurally_resolved_type(expr.span, rcvr_t); let tps = tps.iter().map(|ast_ty| self.to_ty(&ast_ty)).collect::>(); let fn_ty = match self.lookup_method(method_name.span, @@ -2867,7 +2860,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { id: ast::NodeId, sp: Span, expected: Expectation<'tcx>) -> Ty<'tcx> { - self.check_expr_has_type(cond_expr, self.tcx.types.bool); + let cond_ty = self.check_expr_has_type(cond_expr, self.tcx.types.bool); let expected = expected.adjust_for_branches(self); self.check_block_with_expected(then_blk, expected); @@ -2876,8 +2869,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let unit = self.tcx.mk_nil(); let (origin, expected, found, result) = if let Some(else_expr) = opt_else_expr { - self.check_expr_with_expectation(else_expr, expected); - let else_ty = self.expr_ty(else_expr); + let else_ty = self.check_expr_with_expectation(else_expr, expected); let origin = TypeOrigin::IfExpression(sp); // Only try to coerce-unify if we have a then expression @@ -2919,7 +2911,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let if_ty = match result { Ok(ty) => { - if self.expr_ty(cond_expr).references_error() { + if cond_ty.references_error() { self.tcx.types.err } else { ty @@ -2940,9 +2932,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { lvalue_pref: LvaluePreference, base: &'gcx hir::Expr, field: &Spanned) -> Ty<'tcx> { - self.check_expr_with_lvalue_pref(base, lvalue_pref); + let expr_t = self.check_expr_with_lvalue_pref(base, lvalue_pref); let expr_t = self.structurally_resolved_type(expr.span, - self.expr_ty(base)); + expr_t); let mut private_candidate = None; let mut autoderef = self.autoderef(expr.span, expr_t); while let Some((base_t, autoderefs)) = autoderef.next() { @@ -3038,9 +3030,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { lvalue_pref: LvaluePreference, base: &'gcx hir::Expr, idx: codemap::Spanned) -> Ty<'tcx> { - self.check_expr_with_lvalue_pref(base, lvalue_pref); + let expr_t = self.check_expr_with_lvalue_pref(base, lvalue_pref); let expr_t = self.structurally_resolved_type(expr.span, - self.expr_ty(base)); + expr_t); let mut private_candidate = None; let mut tuple_like = false; let mut autoderef = self.autoderef(expr.span, expr_t); @@ -3272,18 +3264,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { base_expr: &'gcx Option>) -> Ty<'tcx> { // Find the relevant variant - let (variant, expr_ty) = if let Some(variant_ty) = self.check_struct_path(path, expr.id, + let (variant, expr_t) = if let Some(variant_ty) = self.check_struct_path(path, expr.id, expr.span) { variant_ty } else { return self.check_struct_fields_on_error(expr.id, fields, base_expr); }; - self.check_expr_struct_fields(expr_ty, path.span, variant, fields, + self.check_expr_struct_fields(expr_t, path.span, variant, fields, base_expr.is_none()); if let &Some(ref base_expr) = base_expr { - self.check_expr_has_type(base_expr, expr_ty); - match expr_ty.sty { + self.check_expr_has_type(base_expr, expr_t); + match expr_t.sty { ty::TyStruct(adt, substs) => { self.tables.borrow_mut().fru_field_types.insert( expr.id, @@ -3300,7 +3292,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } } - expr_ty + expr_t } @@ -3331,8 +3323,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => NoExpectation } }); - self.check_expr_with_expectation(subexpr, expected_inner); - let referent_ty = self.expr_ty(&subexpr); + let referent_ty = self.check_expr_with_expectation(subexpr, expected_inner); self.write_ty(id, tcx.mk_box(referent_ty)) } @@ -3510,7 +3501,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty); - self.require_expr_have_sized_type(&lhs, traits::AssignmentLhsSized); + self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized); if lhs_ty.references_error() || rhs_ty.references_error() { self.write_error(id) @@ -3523,9 +3514,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { id, expr.span, expected) } hir::ExprWhile(ref cond, ref body, _) => { - self.check_expr_has_type(&cond, tcx.types.bool); + let cond_ty = 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) @@ -3714,7 +3704,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::ExprStruct(ref path, ref fields, ref base_expr) => { let ty = self.check_expr_struct(expr, path, fields, base_expr); - self.require_expr_have_sized_type(expr, traits::StructInitializerSized); + self.require_type_is_sized(ty, expr.span, traits::StructInitializerSized); ty } hir::ExprField(ref base, ref field) => { @@ -3735,8 +3725,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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.demand_eqtype(expr.span, index_ty, idx_t); self.write_ty(id, element_ty) } None => { @@ -3865,7 +3854,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn check_decl_initializer(&self, local: &'gcx hir::Local, - init: &'gcx hir::Expr) + init: &'gcx hir::Expr) -> Ty<'tcx> { let ref_bindings = self.tcx.pat_contains_ref_binding(&local.pat); @@ -3884,7 +3873,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { init_ty } else { self.check_expr_coercable_to_type(init, local_ty) - }; + } } pub fn check_decl_local(&self, local: &'gcx hir::Local) { @@ -3892,8 +3881,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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); + let init_ty = self.check_decl_initializer(local, &init); if init_ty.references_error() { self.write_ty(local.id, init_ty); } @@ -3926,17 +3914,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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(); + let expr_t = self.check_expr_has_type(&expr, self.tcx.mk_nil()); + saw_bot = saw_bot || self.type_var_diverges(expr_t); + saw_err = saw_err || expr_t.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(); + let expr_t = self.check_expr(&expr); + saw_bot |= self.type_var_diverges(expr_t); + saw_err |= expr_t.references_error(); } } if saw_bot { @@ -4023,8 +4009,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ety } _ => { - self.check_expr_with_expectation(&e, expected); - self.expr_ty(&e) + self.check_expr_with_expectation(&e, expected) } }; diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index feb3258c88c25..5462826ef9048 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -25,9 +25,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { lhs_expr: &'gcx hir::Expr, rhs_expr: &'gcx hir::Expr) -> Ty<'tcx> { - self.check_expr_with_lvalue_pref(lhs_expr, PreferMutLvalue); + let lhs_ty = self.check_expr_with_lvalue_pref(lhs_expr, PreferMutLvalue); - let lhs_ty = self.resolve_type_vars_with_obligations(self.expr_ty(lhs_expr)); + let lhs_ty = self.resolve_type_vars_with_obligations(lhs_ty); 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); @@ -69,8 +69,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { lhs_expr, rhs_expr); - self.check_expr(lhs_expr); - let lhs_ty = self.resolve_type_vars_with_obligations(self.expr_ty(lhs_expr)); + let lhs_ty = self.check_expr(lhs_expr); + let lhs_ty = self.resolve_type_vars_with_obligations(lhs_ty); let ty = match BinOpCategory::from(op) { BinOpCategory::Shortcircuit => { From c7ea3e8d134b941a0ed2f3d6b535649d081bf92d Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Thu, 18 Aug 2016 14:21:13 +0800 Subject: [PATCH 03/20] Remove redundant error checking around ExprMethodCall --- src/librustc_typeck/check/mod.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 774969daf388a..df789897bf154 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3551,15 +3551,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ret_ty } hir::ExprMethodCall(name, ref tps, ref args) => { - let ty = 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) - } - else { - ty - } + self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref) } hir::ExprCast(ref e, ref t) => { if let hir::TyFixedLengthVec(_, ref count_expr) = t.node { From 06ad8fe261aae7b58b70be58f6a3ac6d5d9d2328 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Thu, 18 Aug 2016 17:16:42 +0800 Subject: [PATCH 04/20] Factor write_ty out of check_binop* --- src/librustc_typeck/check/mod.rs | 6 ++++-- src/librustc_typeck/check/op.rs | 6 ++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index df789897bf154..7a5b2bdeb1638 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3332,10 +3332,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.write_ty(id, typ) } hir::ExprBinary(op, ref lhs, ref rhs) => { - self.check_binop(expr, op, lhs, rhs) + let ty = self.check_binop(expr, op, lhs, rhs); + self.write_ty(id, ty) } hir::ExprAssignOp(op, ref lhs, ref rhs) => { - self.check_binop_assign(expr, op, lhs, rhs) + let ty = self.check_binop_assign(expr, op, lhs, rhs); + self.write_ty(id, ty) } hir::ExprUnary(unop, ref oprnd) => { let expected_inner = match unop { diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 5462826ef9048..af7e12bd48dc2 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -38,7 +38,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } else { return_ty }; - let ty = self.write_ty(expr.id, ty); let tcx = self.tcx; if !tcx.expr_is_lval(lhs_expr) { @@ -72,7 +71,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let lhs_ty = self.check_expr(lhs_expr); let lhs_ty = self.resolve_type_vars_with_obligations(lhs_ty); - let ty = match BinOpCategory::from(op) { + match BinOpCategory::from(op) { BinOpCategory::Shortcircuit => { // && and || are a simple case. self.demand_suptype(lhs_expr.span, tcx.mk_bool(), lhs_ty); @@ -111,8 +110,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { return_ty } - }; - self.write_ty(expr.id, ty) + } } fn enforce_builtin_binop_types(&self, From 91b39b5e65ac66f85bc6be749593690417d0373e Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Thu, 18 Aug 2016 21:09:21 +0800 Subject: [PATCH 05/20] Factor write_ty out of more checking functions --- src/librustc_typeck/check/_match.rs | 6 ++++-- src/librustc_typeck/check/mod.rs | 27 +++++++++++---------------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 2bb0abfab4ee7..b69afbf8ff03d 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -473,8 +473,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; } - - self.write_ty(expr.id, result_ty) + + result_ty } } @@ -545,6 +545,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Type check the path. let pat_ty = self.instantiate_value_path(segments, opt_ty, def, pat.span, pat.id); + self.write_ty(pat.id, pat_ty); self.demand_suptype(pat.span, expected, pat_ty); } @@ -603,6 +604,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Type check the path. let pat_ty = self.instantiate_value_path(segments, opt_ty, def, pat.span, pat.id); + self.write_ty(pat.id, pat_ty); let pat_ty = if pat_ty.is_fn() { // Replace constructor type with constructed type for tuple struct patterns. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7a5b2bdeb1638..4d5160a4de6b3 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2857,7 +2857,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { cond_expr: &'gcx hir::Expr, then_blk: &'gcx hir::Block, opt_else_expr: Option<&'gcx hir::Expr>, - id: ast::NodeId, sp: Span, expected: Expectation<'tcx>) -> Ty<'tcx> { let cond_ty = self.check_expr_has_type(cond_expr, self.tcx.types.bool); @@ -2909,7 +2908,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { })) }; - let if_ty = match result { + match result { Ok(ty) => { if cond_ty.references_error() { self.tcx.types.err @@ -2921,9 +2920,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.report_mismatched_types(origin, expected, found, e); self.tcx.types.err } - }; - - self.write_ty(id, if_ty) + } } // Check field access expressions @@ -3447,7 +3444,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.instantiate_value_path(segments, opt_ty, def, expr.span, id) } else { self.set_tainted_by_errors(); - self.write_error(id) + tcx.types.err }; // We always require that the type provided as the value for @@ -3455,7 +3452,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.opt_node_ty_substs(expr.id, |item_substs| { self.add_wf_bounds(&item_substs.substs, expr); }); - ty + + self.write_ty(id, ty) } hir::ExprInlineAsm(_, ref outputs, ref inputs) => { for output in outputs { @@ -3512,8 +3510,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } 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) + let if_ty = self.check_then_else(&cond, &then_blk, opt_else_expr.as_ref().map(|e| &**e), + expr.span, expected); + self.write_ty(id, if_ty) } hir::ExprWhile(ref cond, ref body, _) => { let cond_ty = self.check_expr_has_type(&cond, tcx.types.bool); @@ -3535,7 +3534,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } hir::ExprMatch(ref discrim, ref arms, match_src) => { - self.check_match(expr, &discrim, arms, expected, match_src) + let result_ty = self.check_match(expr, &discrim, arms, expected, match_src); + self.write_ty(expr.id, result_ty) } hir::ExprClosure(capture, ref decl, ref body, _) => { self.check_expr_closure(expr, capture, &decl, &body, expected) @@ -3571,16 +3571,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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. - let ty = 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); - ty + self.write_ty(id, t_cast) } Err(ErrorReported) => { self.write_error(id) @@ -4328,7 +4324,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("instantiate_value_path: type of {:?} is {:?}", node_id, ty_substituted); - self.write_ty(node_id, ty_substituted); self.write_substs(node_id, ty::ItemSubsts { substs: substs }); From f22dd2e2d9f29869ff7956cecb5a616ce50e3e89 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Thu, 18 Aug 2016 22:07:57 +0800 Subject: [PATCH 06/20] Factor write_ty out of field/indexing methods --- src/librustc_typeck/check/mod.rs | 38 ++++++++++++++++---------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 4d5160a4de6b3..30f4202fccbf0 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2942,9 +2942,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let field_ty = self.field_ty(expr.span, field, substs); if field.vis.is_accessible_from(self.body_id, &self.tcx().map) { autoderef.finalize(lvalue_pref, Some(base)); - let ty = self.write_ty(expr.id, field_ty); self.write_autoderef_adjustment(base.id, autoderefs); - return ty; + return field_ty; } private_candidate = Some((base_def.did, field_ty)); } @@ -2956,7 +2955,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some((did, field_ty)) = private_candidate { let struct_path = self.tcx().item_path_str(did); - let ty = self.write_ty(expr.id, field_ty); let msg = format!("field `{}` of struct `{}` is private", field.node, struct_path); let mut err = self.tcx().sess.struct_span_err(expr.span, &msg); // Also check if an accessible method exists, which is often what is meant. @@ -2965,9 +2963,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { field.node)); } err.emit(); - ty + field_ty } else if field.node == keywords::Invalid.name() { - self.write_error(expr.id) + self.tcx().types.err } else if self.method_exists(field.span, field.node, expr_t, expr.id, true) { self.type_error_struct(field.span, |actual| { format!("attempted to take value of method `{}` on type \ @@ -2976,7 +2974,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .help("maybe a `()` to call it is missing? \ If not, try an anonymous function") .emit(); - self.write_error(expr.id) + self.tcx().types.err } else { let mut err = self.type_error_struct(expr.span, |actual| { format!("attempted access of field `{}` on type `{}`, \ @@ -2994,7 +2992,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => {} } err.emit(); - self.write_error(expr.id) + self.tcx().types.err } } @@ -3059,9 +3057,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(field_ty) = field { autoderef.finalize(lvalue_pref, Some(base)); - let ty = self.write_ty(expr.id, field_ty); self.write_autoderef_adjustment(base.id, autoderefs); - return ty; + return field_ty; } } autoderef.unambiguous_final_ty(); @@ -3070,7 +3067,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let struct_path = self.tcx().item_path_str(did); let msg = format!("field `{}` of struct `{}` is private", idx.node, struct_path); self.tcx().sess.span_err(expr.span, &msg); - return self.write_ty(expr.id, field_ty) + return field_ty; } self.type_error_message( @@ -3090,7 +3087,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }, expr_t); - self.write_error(expr.id) + self.tcx().types.err } fn report_unknown_field(&self, @@ -3698,25 +3695,27 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty } hir::ExprField(ref base, ref field) => { - self.check_field(expr, lvalue_pref, &base, field) + let ty = self.check_field(expr, lvalue_pref, &base, field); + self.write_ty(id, ty) } hir::ExprTupField(ref base, idx) => { - self.check_tup_field(expr, lvalue_pref, &base, idx) + let ty = self.check_tup_field(expr, lvalue_pref, &base, idx); + self.write_ty(id, ty) } hir::ExprIndex(ref base, ref idx) => { let base_t = self.check_expr_with_lvalue_pref(&base, lvalue_pref); let idx_t = self.check_expr(&idx); - if base_t.references_error() { - self.write_ty(id, base_t) + let ty = if base_t.references_error() { + base_t } else if idx_t.references_error() { - self.write_ty(id, idx_t) + 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)) => { self.demand_eqtype(expr.span, index_ty, idx_t); - self.write_ty(id, element_ty) + element_ty } None => { self.check_expr_has_type(&idx, self.tcx.types.err); @@ -3752,10 +3751,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } err.emit(); - self.write_ty(id, self.tcx().types.err) + self.tcx().types.err } } - } + }; + self.write_ty(id, ty) } }; From 144b8cf5db99df4f6132f1ac5b59184f8907965d Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Thu, 18 Aug 2016 22:51:01 +0800 Subject: [PATCH 07/20] Factor write_ty out of check_struct_expr --- src/librustc_typeck/check/_match.rs | 1 + src/librustc_typeck/check/mod.rs | 16 +++++----------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index b69afbf8ff03d..838cf36b8853e 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -497,6 +497,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } return; }; + self.write_ty(pat.id, pat_ty); // Type check the path. self.demand_eqtype(pat.span, expected, pat_ty); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 30f4202fccbf0..f70d7c577486c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1711,7 +1711,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.add_obligations_for_parameters(cause, &bounds); let ty_substituted = self.instantiate_type_scheme(path.span, substs, &ty); - self.write_ty(node_id, ty_substituted); self.write_substs(node_id, ty::ItemSubsts { substs: substs }); @@ -3190,12 +3189,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } fn check_struct_fields_on_error(&self, - id: ast::NodeId, fields: &'gcx [hir::Field], - base_expr: &'gcx Option>) -> Ty<'tcx> { - // Make sure to still write the types - // otherwise we might ICE - let ty = self.write_error(id); + base_expr: &'gcx Option>) { for field in fields { self.check_expr(&field.expr); } @@ -3205,7 +3200,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }, None => {} } - ty } pub fn check_struct_path(&self, @@ -3262,7 +3256,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr.span) { variant_ty } else { - return self.check_struct_fields_on_error(expr.id, fields, base_expr); + self.check_struct_fields_on_error(fields, base_expr); + return self.tcx().types.err; }; self.check_expr_struct_fields(expr_t, path.span, variant, fields, @@ -3286,6 +3281,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } } + self.require_type_is_sized(expr_t, expr.span, traits::StructInitializerSized); expr_t } @@ -3690,9 +3686,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } hir::ExprStruct(ref path, ref fields, ref base_expr) => { let ty = self.check_expr_struct(expr, path, fields, base_expr); - - self.require_type_is_sized(ty, expr.span, traits::StructInitializerSized); - ty + self.write_ty(id, ty) } hir::ExprField(ref base, ref field) => { let ty = self.check_field(expr, lvalue_pref, &base, field); From 21720641dc4d3b921eb5be2a4c66900003a742dd Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Thu, 18 Aug 2016 23:30:11 +0800 Subject: [PATCH 08/20] Factor write_ty out of check_expr_closure --- src/librustc_typeck/check/closure.rs | 4 +--- src/librustc_typeck/check/mod.rs | 3 ++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 1f4201aa39cdd..9e41d1b5676e4 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -70,8 +70,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.parameter_environment.free_substs, upvar_tys); - let ty = 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); let fn_sig = @@ -94,7 +92,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { None => { } } - ty + closure_type } fn deduce_expectations_from_expected_type(&self, expected_ty: Ty<'tcx>) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index f70d7c577486c..4c400f1092c5f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3531,7 +3531,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.write_ty(expr.id, result_ty) } hir::ExprClosure(capture, ref decl, ref body, _) => { - self.check_expr_closure(expr, capture, &decl, &body, expected) + let ty = self.check_expr_closure(expr, capture, &decl, &body, expected); + self.write_ty(id, ty) } hir::ExprBlock(ref b) => { self.check_block_with_expected(&b, expected); From 9cd8d7a24f73e7de91cc3ba4461eeb6fe8a086f3 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Thu, 18 Aug 2016 23:52:05 +0800 Subject: [PATCH 09/20] Factor write_ty out of function checking functions --- src/librustc_typeck/check/callee.rs | 18 +++++++++++------- src/librustc_typeck/check/mod.rs | 10 ++++------ 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index bc3c5aba7100b..5bd4f13a1119c 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -15,7 +15,7 @@ use CrateCtxt; use middle::cstore::LOCAL_CRATE; use hir::def::Def; use hir::def_id::DefId; -use rustc::infer; +use rustc::{infer, traits}; use rustc::ty::{self, LvaluePreference, Ty}; use syntax::parse::token; use syntax::ptr::P; @@ -56,7 +56,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let callee_ty = autoderef.unambiguous_final_ty(); autoderef.finalize(LvaluePreference::NoPreference, Some(callee_expr)); - match result { + let output = 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) @@ -74,7 +74,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.confirm_overloaded_call(call_expr, callee_expr, arg_exprs, expected, method_callee) } - } + }; + + // we must check that return type of called functions is WF: + self.register_wf_obligation(output, call_expr.span, traits::MiscObligation); + + output } fn try_overloaded_call_step(&self, @@ -244,7 +249,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn_sig.variadic, TupleArgumentsFlag::DontTupleArguments); - self.write_ty(call_expr.id, fn_sig.output) + fn_sig.output } fn confirm_deferred_closure_call(&self, @@ -271,7 +276,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn_sig.variadic, TupleArgumentsFlag::TupleArguments); - self.write_ty(call_expr.id, fn_sig.output) + fn_sig.output } fn confirm_overloaded_call(&self, @@ -288,10 +293,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { arg_exprs, TupleArgumentsFlag::TupleArguments, expected); - let ty = self.write_ty(call_expr.id, output_type); self.write_overloaded_call_method_map(call_expr, method_callee); - ty + output_type } fn write_overloaded_call_method_map(&self, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 4c400f1092c5f..8406b491737ec 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2847,7 +2847,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { DontTupleArguments, expected); - self.write_ty(expr.id, ret_ty) + ret_ty } // A generic function for checking the then and else in an if @@ -3541,13 +3541,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } hir::ExprCall(ref callee, ref args) => { let ret_ty = self.check_call(expr, &callee, &args[..], expected); - - // we must check that return type of called functions is WF: - self.register_wf_obligation(ret_ty, expr.span, traits::MiscObligation); - ret_ty + self.write_ty(id, ret_ty) } hir::ExprMethodCall(name, ref tps, ref args) => { - self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref) + let ret_ty = self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref); + self.write_ty(id, ret_ty) } hir::ExprCast(ref e, ref t) => { if let hir::TyFixedLengthVec(_, ref count_expr) = t.node { From adb19ff277262ce629e092feabdc5f5f5a2ac408 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Fri, 19 Aug 2016 00:13:15 +0800 Subject: [PATCH 10/20] Add AdjustNeverToAny in check_expr --- src/librustc_typeck/check/mod.rs | 130 ++++++++++++++----------------- 1 file changed, 57 insertions(+), 73 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 8406b491737ec..2a12b7055d4ed 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1530,21 +1530,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } #[inline] - pub fn write_ty(&self, node_id: ast::NodeId, ty: Ty<'tcx>) -> Ty<'tcx> { + pub fn write_ty(&self, node_id: ast::NodeId, ty: Ty<'tcx>) { debug!("write_ty({}, {:?}) in fcx {}", node_id, ty, self.tag()); self.tables.borrow_mut().node_types.insert(node_id, ty); - - // Add adjustments to !-expressions - if ty.is_never() { - if let Some(hir::map::NodeExpr(_)) = self.tcx.map.find(node_id) { - let adj_ty = self.next_diverging_ty_var(); - let adj = adjustment::AdjustNeverToAny(adj_ty); - self.write_adjustment(node_id, adj); - return adj_ty; - } - } - ty } pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) { @@ -1717,16 +1706,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty_substituted } - pub fn write_nil(&self, node_id: ast::NodeId) -> Ty<'tcx> { - self.write_ty(node_id, self.tcx.mk_nil()) + pub fn write_nil(&self, node_id: ast::NodeId) { + self.write_ty(node_id, self.tcx.mk_nil()); } - pub fn write_never(&self, node_id: ast::NodeId) -> Ty<'tcx> { - self.write_ty(node_id, self.tcx.types.never) + pub fn write_never(&self, node_id: ast::NodeId) { + self.write_ty(node_id, self.tcx.types.never); } - pub fn write_error(&self, node_id: ast::NodeId) -> Ty<'tcx> { - self.write_ty(node_id, self.tcx.types.err) + pub fn write_error(&self, node_id: ast::NodeId) { + self.write_ty(node_id, self.tcx.types.err); } pub fn require_type_meets(&self, @@ -3314,20 +3303,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }); let referent_ty = self.check_expr_with_expectation(subexpr, expected_inner); - self.write_ty(id, tcx.mk_box(referent_ty)) + tcx.mk_box(referent_ty) } hir::ExprLit(ref lit) => { - let typ = self.check_lit(&lit, expected); - self.write_ty(id, typ) + self.check_lit(&lit, expected) } hir::ExprBinary(op, ref lhs, ref rhs) => { - let ty = self.check_binop(expr, op, lhs, rhs); - self.write_ty(id, ty) + self.check_binop(expr, op, lhs, rhs) } hir::ExprAssignOp(op, ref lhs, ref rhs) => { - let ty = self.check_binop_assign(expr, op, lhs, rhs); - self.write_ty(id, ty) + self.check_binop_assign(expr, op, lhs, rhs) } hir::ExprUnary(unop, ref oprnd) => { let expected_inner = match unop { @@ -3386,7 +3372,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } } - self.write_ty(id, oprnd_t) + oprnd_t } hir::ExprAddrOf(mutbl, ref oprnd) => { let hint = expected.only_has_type(self).map_or(NoExpectation, |ty| { @@ -3408,7 +3394,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let ty = self.check_expr_with_expectation_and_lvalue_pref(&oprnd, hint, lvalue_pref); let tm = ty::TypeAndMut { ty: ty, mutbl: mutbl }; - let oprnd_t = if tm.ty.references_error() { + if tm.ty.references_error() { tcx.types.err } else { // Note: at this point, we cannot say what the best lifetime @@ -3426,8 +3412,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // as long as it needs to live. let region = self.next_region_var(infer::AddrOfRegion(expr.span)); tcx.mk_ref(region, tm) - }; - self.write_ty(id, oprnd_t) + } } hir::ExprPath(ref opt_qself, ref path) => { let opt_self_ty = opt_qself.as_ref().map(|qself| self.to_ty(&qself.ty)); @@ -3446,7 +3431,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.add_wf_bounds(&item_substs.substs, expr); }); - self.write_ty(id, ty) + ty } hir::ExprInlineAsm(_, ref outputs, ref inputs) => { for output in outputs { @@ -3455,10 +3440,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { for input in inputs { self.check_expr(input); } - self.write_nil(id) + tcx.mk_nil() } - hir::ExprBreak(_) => { self.write_never(id) } - hir::ExprAgain(_) => { self.write_never(id) } + hir::ExprBreak(_) => { tcx.types.never } + hir::ExprAgain(_) => { tcx.types.never } hir::ExprRet(ref expr_opt) => { if let Some(ref e) = *expr_opt { self.check_expr_coercable_to_type(&e, self.ret_ty); @@ -3476,7 +3461,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .emit(); } } - self.write_never(id) + tcx.types.never } hir::ExprAssign(ref lhs, ref rhs) => { let lhs_ty = self.check_expr_with_lvalue_pref(&lhs, PreferMutLvalue); @@ -3497,55 +3482,49 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized); if lhs_ty.references_error() || rhs_ty.references_error() { - self.write_error(id) + tcx.types.err } else { - self.write_nil(id) + tcx.mk_nil() } } hir::ExprIf(ref cond, ref then_blk, ref opt_else_expr) => { - let if_ty = self.check_then_else(&cond, &then_blk, opt_else_expr.as_ref().map(|e| &**e), - expr.span, expected); - self.write_ty(id, if_ty) + self.check_then_else(&cond, &then_blk, opt_else_expr.as_ref().map(|e| &**e), + expr.span, expected) } hir::ExprWhile(ref cond, ref body, _) => { let cond_ty = self.check_expr_has_type(&cond, tcx.types.bool); self.check_block_no_value(&body); let body_ty = self.node_ty(body.id); if cond_ty.references_error() || body_ty.references_error() { - self.write_error(id) + tcx.types.err } else { - self.write_nil(id) + tcx.mk_nil() } } hir::ExprLoop(ref body, _) => { self.check_block_no_value(&body); if !may_break(tcx, expr.id, &body) { - self.write_never(id) + tcx.types.never } else { - self.write_nil(id) + tcx.mk_nil() } } hir::ExprMatch(ref discrim, ref arms, match_src) => { - let result_ty = self.check_match(expr, &discrim, arms, expected, match_src); - self.write_ty(expr.id, result_ty) + self.check_match(expr, &discrim, arms, expected, match_src) } hir::ExprClosure(capture, ref decl, ref body, _) => { - let ty = self.check_expr_closure(expr, capture, &decl, &body, expected); - self.write_ty(id, ty) + self.check_expr_closure(expr, capture, &decl, &body, expected) } hir::ExprBlock(ref b) => { self.check_block_with_expected(&b, expected); - let ty = self.node_ty(b.id); - self.write_ty(id, ty) + self.node_ty(b.id) } hir::ExprCall(ref callee, ref args) => { - let ret_ty = self.check_call(expr, &callee, &args[..], expected); - self.write_ty(id, ret_ty) + self.check_call(expr, &callee, &args[..], expected) } hir::ExprMethodCall(name, ref tps, ref args) => { - let ret_ty = self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref); - self.write_ty(id, ret_ty) + self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref) } hir::ExprCast(ref e, ref t) => { if let hir::TyFixedLengthVec(_, ref count_expr) = t.node { @@ -3561,17 +3540,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Eagerly check for some obvious errors. if t_expr.references_error() || t_cast.references_error() { - self.write_error(id) + tcx.types.err } else { // 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); - self.write_ty(id, t_cast) + t_cast } Err(ErrorReported) => { - self.write_error(id) + tcx.types.err } } } @@ -3579,7 +3558,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::ExprType(ref e, ref t) => { let typ = self.to_ty(&t); self.check_expr_eq_type(&e, typ); - self.write_ty(id, typ) + typ } hir::ExprVec(ref args) => { let uty = expected.to_option(self).and_then(|uty| { @@ -3611,7 +3590,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } } - self.write_ty(id, tcx.mk_array(unified, args.len())) + tcx.mk_array(unified, args.len()) } hir::ExprRepeat(ref element, ref count_expr) => { self.check_expr_has_type(&count_expr, tcx.types.usize); @@ -3647,10 +3626,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } if element_ty.references_error() { - self.write_error(id) + tcx.types.err } else { - let t = tcx.mk_array(t, count); - self.write_ty(id, t) + tcx.mk_array(t, count) } } hir::ExprTup(ref elts) => { @@ -3677,29 +3655,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { t }).collect(); if err_field { - self.write_error(id) + tcx.types.err } else { - let typ = tcx.mk_tup(elt_ts); - self.write_ty(id, typ) + tcx.mk_tup(elt_ts) } } hir::ExprStruct(ref path, ref fields, ref base_expr) => { - let ty = self.check_expr_struct(expr, path, fields, base_expr); - self.write_ty(id, ty) + self.check_expr_struct(expr, path, fields, base_expr) } hir::ExprField(ref base, ref field) => { - let ty = self.check_field(expr, lvalue_pref, &base, field); - self.write_ty(id, ty) + self.check_field(expr, lvalue_pref, &base, field) } hir::ExprTupField(ref base, idx) => { - let ty = self.check_tup_field(expr, lvalue_pref, &base, idx); - self.write_ty(id, ty) + self.check_tup_field(expr, lvalue_pref, &base, idx) } hir::ExprIndex(ref base, ref idx) => { let base_t = self.check_expr_with_lvalue_pref(&base, lvalue_pref); let idx_t = self.check_expr(&idx); - let ty = if base_t.references_error() { + if base_t.references_error() { base_t } else if idx_t.references_error() { idx_t @@ -3747,16 +3721,26 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.tcx().types.err } } - }; - self.write_ty(id, ty) + } } }; + self.write_ty(id, ty); debug!("type of expr({}) {} is...", expr.id, pprust::expr_to_string(expr)); debug!("... {:?}, expected is {:?}", ty, expected); + + // Add adjustments to !-expressions + if ty.is_never() { + if let Some(hir::map::NodeExpr(_)) = self.tcx.map.find(id) { + let adj_ty = self.next_diverging_ty_var(); + let adj = adjustment::AdjustNeverToAny(adj_ty); + self.write_adjustment(id, adj); + return adj_ty; + } + } ty } From 1c3e8b0a1c15d4cb7315a7067c19901c2cf66e0c Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Fri, 19 Aug 2016 00:24:32 +0800 Subject: [PATCH 11/20] Tidy --- src/librustc_typeck/check/_match.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 838cf36b8853e..5e7c499671c34 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -473,7 +473,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; } - + result_ty } } From f120c71775994e4fb94941cbc5539f6d5ffddced Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Fri, 19 Aug 2016 14:12:37 +0800 Subject: [PATCH 12/20] Tidy. Rename variables. --- src/librustc_typeck/check/_match.rs | 6 +++--- src/librustc_typeck/check/mod.rs | 26 +++++++++++++------------- src/librustc_typeck/check/op.rs | 3 ++- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 5e7c499671c34..763e92b69baf0 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -37,11 +37,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.write_ty(pat.id, expected); } PatKind::Lit(ref lt) => { - let expr_t = self.check_expr(<); + let ty = self.check_expr(<); // 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_t; + let mut pat_ty = 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); @@ -62,7 +62,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // 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_t` is + // subtyping is irrelevant, and for strings `ty` is // type is `&'static str`, so if we say that // // &'static str <: expected diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 2a12b7055d4ed..a8c8a10dc568e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3241,19 +3241,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { base_expr: &'gcx Option>) -> Ty<'tcx> { // Find the relevant variant - let (variant, expr_t) = if let Some(variant_ty) = self.check_struct_path(path, expr.id, - expr.span) { + let (variant, struct_ty) = if let Some(variant_ty) = self.check_struct_path(path, expr.id, + expr.span) { variant_ty } else { self.check_struct_fields_on_error(fields, base_expr); return self.tcx().types.err; }; - self.check_expr_struct_fields(expr_t, path.span, variant, fields, + self.check_expr_struct_fields(struct_ty, path.span, variant, fields, base_expr.is_none()); if let &Some(ref base_expr) = base_expr { - self.check_expr_has_type(base_expr, expr_t); - match expr_t.sty { + self.check_expr_has_type(base_expr, struct_ty); + match struct_ty.sty { ty::TyStruct(adt, substs) => { self.tables.borrow_mut().fru_field_types.insert( expr.id, @@ -3270,8 +3270,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } } - self.require_type_is_sized(expr_t, expr.span, traits::StructInitializerSized); - expr_t + self.require_type_is_sized(struct_ty, expr.span, traits::StructInitializerSized); + struct_ty } @@ -3881,15 +3881,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::StmtExpr(ref expr, id) => { node_id = id; // Check with expected type of () - let expr_t = self.check_expr_has_type(&expr, self.tcx.mk_nil()); - saw_bot = saw_bot || self.type_var_diverges(expr_t); - saw_err = saw_err || expr_t.references_error(); + let ty = self.check_expr_has_type(&expr, self.tcx.mk_nil()); + saw_bot = saw_bot || self.type_var_diverges(ty); + saw_err = saw_err || ty.references_error(); } hir::StmtSemi(ref expr, id) => { node_id = id; - let expr_t = self.check_expr(&expr); - saw_bot |= self.type_var_diverges(expr_t); - saw_err |= expr_t.references_error(); + let ty = self.check_expr(&expr); + saw_bot |= self.type_var_diverges(ty); + saw_err |= ty.references_error(); } } if saw_bot { diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index af7e12bd48dc2..411bd7e7b5ca1 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -32,7 +32,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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); - let ty = if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) { + let 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.tcx.mk_nil() } else { From f54c47d34b0d8c898529c479a270ab034ce36f78 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Fri, 19 Aug 2016 14:17:00 +0800 Subject: [PATCH 13/20] Move check_expr match block into its own method --- src/librustc_typeck/check/mod.rs | 45 ++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a8c8a10dc568e..3fbfd2aedb466 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3291,10 +3291,35 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { lvalue_pref: LvaluePreference) -> Ty<'tcx> { debug!(">> typechecking: expr={:?} expected={:?}", expr, expected); + let ty = self.check_expr_kind(expr, expected, lvalue_pref); + self.write_ty(expr.id, ty); + + debug!("type of expr({}) {} is...", expr.id, + pprust::expr_to_string(expr)); + debug!("... {:?}, expected is {:?}", + ty, + expected); + + // Add adjustments to !-expressions + if ty.is_never() { + if let Some(hir::map::NodeExpr(_)) = self.tcx.map.find(expr.id) { + let adj_ty = self.next_diverging_ty_var(); + let adj = adjustment::AdjustNeverToAny(adj_ty); + self.write_adjustment(expr.id, adj); + return adj_ty; + } + } + ty + } + + fn check_expr_kind(&self, + expr: &'gcx hir::Expr, + expected: Expectation<'tcx>, + lvalue_pref: LvaluePreference) -> Ty<'tcx> { let tcx = self.tcx; let id = expr.id; - let ty = match expr.node { + match expr.node { hir::ExprBox(ref subexpr) => { let expected_inner = expected.to_option(self).map_or(NoExpectation, |ty| { match ty.sty { @@ -3723,25 +3748,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } } - }; - self.write_ty(id, ty); - - debug!("type of expr({}) {} is...", expr.id, - pprust::expr_to_string(expr)); - debug!("... {:?}, expected is {:?}", - ty, - expected); - - // Add adjustments to !-expressions - if ty.is_never() { - if let Some(hir::map::NodeExpr(_)) = self.tcx.map.find(id) { - let adj_ty = self.next_diverging_ty_var(); - let adj = adjustment::AdjustNeverToAny(adj_ty); - self.write_adjustment(id, adj); - return adj_ty; - } } - ty } // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary. From 8c6086a0a3f0de3cd31b01eb223d36cd15314d6f Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Fri, 19 Aug 2016 14:41:25 +0800 Subject: [PATCH 14/20] check_block_with_expected returns the checked type --- src/librustc_typeck/check/mod.rs | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 3fbfd2aedb466..79dd951a5d85e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2850,8 +2850,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let cond_ty = self.check_expr_has_type(cond_expr, self.tcx.types.bool); let expected = expected.adjust_for_branches(self); - self.check_block_with_expected(then_blk, expected); - let then_ty = self.node_ty(then_blk.id); + let then_ty = self.check_block_with_expected(then_blk, expected); let unit = self.tcx.mk_nil(); let (origin, expected, found, result) = @@ -3542,8 +3541,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_expr_closure(expr, capture, &decl, &body, expected) } hir::ExprBlock(ref b) => { - self.check_block_with_expected(&b, expected); - self.node_ty(b.id) + self.check_block_with_expected(&b, expected) } hir::ExprCall(ref callee, ref args) => { self.check_call(expr, &callee, &args[..], expected) @@ -3911,8 +3909,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } 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); + let blkty = self.check_block_with_expected(blk, ExpectHasType(self.tcx.mk_nil())); if blkty.references_error() { self.write_error(blk.id); } else { @@ -3923,7 +3920,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn check_block_with_expected(&self, blk: &'gcx hir::Block, - expected: Expectation<'tcx>) { + expected: Expectation<'tcx>) -> Ty<'tcx> { let prev = { let mut fcx_ps = self.ps.borrow_mut(); let unsafety_state = fcx_ps.recurse(blk); @@ -3960,13 +3957,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { s_ty.is_never(); any_err = any_err || s_ty.references_error(); } - match blk.expr { + let ty = match blk.expr { None => if any_err { - self.write_error(blk.id); + self.tcx.types.err } else if any_diverges { - self.write_ty(blk.id, self.next_diverging_ty_var()); + self.next_diverging_ty_var() } else { - self.write_nil(blk.id); + self.tcx.mk_nil() }, Some(ref e) => { if any_diverges && !warned { @@ -3988,16 +3985,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if any_err { - self.write_error(blk.id); + self.tcx.types.err } else if any_diverges { - self.write_ty(blk.id, self.next_diverging_ty_var()); + self.next_diverging_ty_var() } else { - self.write_ty(blk.id, ety); + ety } } }; + self.write_ty(blk.id, ty); *self.ps.borrow_mut() = prev; + ty } // Instantiates the given path, which must refer to an item with the given From c5ff28cd14bf90b45f97d370538d792693036b27 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Sat, 27 Aug 2016 20:06:47 +0800 Subject: [PATCH 15/20] Factor write_ty out of pattern-matching functions --- src/librustc_typeck/check/_match.rs | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 763e92b69baf0..35d77e8c2adeb 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -54,8 +54,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - 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 @@ -69,6 +67,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // // that's equivalent to there existing a LUB. self.demand_suptype(pat.span, expected, pat_ty); + self.write_ty(pat.id, pat_ty); } PatKind::Range(ref begin, ref end) => { let lhs_ty = self.check_expr(begin); @@ -101,11 +100,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // 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); self.demand_eqtype(pat.span, expected, rhs_ty); + self.write_ty(pat.id, common_type); } PatKind::Binding(bm, _, ref sub) => { let typ = self.local_ty(pat.span, pat.id); @@ -132,8 +130,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - 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 match tcx.expect_def(pat.id) { @@ -150,6 +146,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(ref p) = *sub { self.check_pat(&p, expected); } + + self.write_ty(pat.id, typ); } PatKind::TupleStruct(ref path, ref subpats, ddpos) => { self.check_pat_tuple_struct(pat, path, &subpats, ddpos, expected); @@ -174,11 +172,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let element_tys: Vec<_> = (0 .. max_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 (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { self.check_pat(elem, &element_tys[i]); } + self.write_ty(pat.id, pat_ty); } PatKind::Box(ref inner) => { let inner_ty = self.next_ty_var(); @@ -189,11 +187,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // 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); + self.write_ty(pat.id, uniq_ty); } else { - self.write_error(pat.id); self.check_pat(&inner, tcx.types.err); + self.write_error(pat.id); } } PatKind::Ref(ref inner, mutbl) => { @@ -221,11 +219,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; - self.write_ty(pat.id, rptr_ty); self.check_pat(&inner, inner_ty); + self.write_ty(pat.id, rptr_ty); } else { - self.write_error(pat.id); self.check_pat(&inner, tcx.types.err); + self.write_error(pat.id); } } PatKind::Vec(ref before, ref slice, ref after) => { @@ -277,8 +275,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; - self.write_ty(pat.id, expected_ty); - for elt in before { self.check_pat(&elt, inner_ty); } @@ -288,6 +284,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { for elt in after { self.check_pat(&elt, inner_ty); } + self.write_ty(pat.id, expected_ty); } } From 1749fda9c04fdb051c82904b522eb79697bbf1c0 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Sat, 27 Aug 2016 20:34:37 +0800 Subject: [PATCH 16/20] Factor write_ty out of more pattern-checking functions --- src/librustc_typeck/check/_match.rs | 42 ++++++++++++++--------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 35d77e8c2adeb..ee66597e72a46 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -150,14 +150,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.write_ty(pat.id, typ); } PatKind::TupleStruct(ref path, ref subpats, ddpos) => { - self.check_pat_tuple_struct(pat, path, &subpats, ddpos, expected); + let pat_ty = self.check_pat_tuple_struct(pat, path, &subpats, ddpos, expected); + write_ty(pat.id, pat_ty); } PatKind::Path(ref opt_qself, ref path) => { let opt_qself_ty = opt_qself.as_ref().map(|qself| self.to_ty(&qself.ty)); - self.check_pat_path(pat, opt_qself_ty, path, expected); + let pat_ty = self.check_pat_path(pat, opt_qself_ty, path, expected); + write_ty(pat.id, pat_ty); } PatKind::Struct(ref path, ref fields, etc) => { - self.check_pat_struct(pat, path, fields, etc, expected); + let pat_ty = self.check_pat_struct(pat, path, fields, etc, expected); + write_ty(pat.id, pat_ty); } PatKind::Tuple(ref elements, ddpos) => { let mut expected_len = elements.len(); @@ -481,40 +484,38 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { path: &hir::Path, fields: &'gcx [Spanned], etc: bool, - expected: Ty<'tcx>) + expected: Ty<'tcx>) -> Ty<'tcx> { // Resolve the path and check the definition for errors. let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(path, pat.id, pat.span) { variant_ty } else { - self.write_error(pat.id); for field in fields { self.check_pat(&field.node.pat, self.tcx.types.err); } - return; + return tcx.types.err; }; - self.write_ty(pat.id, pat_ty); // Type check the path. self.demand_eqtype(pat.span, expected, pat_ty); // Type check subpatterns. self.check_struct_pat_fields(pat_ty, pat.span, variant, fields, etc); + pat_ty } fn check_pat_path(&self, pat: &hir::Pat, opt_self_ty: Option>, path: &hir::Path, - expected: Ty<'tcx>) + expected: Ty<'tcx>) -> Ty<'tcx> { let tcx = self.tcx; let report_unexpected_def = || { span_err!(tcx.sess, pat.span, E0533, "`{}` does not name a unit variant, unit struct or a constant", pprust::path_to_string(path)); - self.write_error(pat.id); }; // Resolve the path and check the definition for errors. @@ -523,18 +524,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match def { Def::Err => { self.set_tainted_by_errors(); - self.write_error(pat.id); - return; + return tcx.types.err; } Def::Method(..) => { report_unexpected_def(); - return; + return tcx.types.err; } Def::Variant(..) | Def::Struct(..) => { let variant = tcx.expect_variant_def(def); if variant.kind != VariantKind::Unit { report_unexpected_def(); - return; + return tcx.types.err; } } Def::Const(..) | Def::AssociatedConst(..) => {} // OK @@ -543,8 +543,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Type check the path. let pat_ty = self.instantiate_value_path(segments, opt_ty, def, pat.span, pat.id); - self.write_ty(pat.id, pat_ty); self.demand_suptype(pat.span, expected, pat_ty); + pat_ty } fn check_pat_tuple_struct(&self, @@ -552,11 +552,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { path: &hir::Path, subpats: &'gcx [P], ddpos: Option, - expected: Ty<'tcx>) + expected: Ty<'tcx>) -> Ty<'tcx> { let tcx = self.tcx; let on_error = || { - self.write_error(pat.id); for pat in subpats { self.check_pat(&pat, tcx.types.err); } @@ -580,11 +579,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Def::Err => { self.set_tainted_by_errors(); on_error(); - return; + return tcx.types.err; } Def::Const(..) | Def::AssociatedConst(..) | Def::Method(..) => { report_unexpected_def(false); - return; + return tcx.types.err; } Def::Variant(..) | Def::Struct(..) => { tcx.expect_variant_def(def) @@ -597,13 +596,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { report_unexpected_def(true); } else if variant.kind != VariantKind::Tuple { report_unexpected_def(false); - return; + return tcx.types.err; } // Type check the path. let pat_ty = self.instantiate_value_path(segments, opt_ty, def, pat.span, pat.id); - self.write_ty(pat.id, pat_ty); - let pat_ty = if pat_ty.is_fn() { // Replace constructor type with constructed type for tuple struct patterns. tcx.no_late_bound_regions(&pat_ty.fn_ret()).unwrap() @@ -611,7 +608,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Leave the type as is for unit structs (backward compatibility). pat_ty }; - self.write_ty(pat.id, pat_ty); self.demand_eqtype(pat.span, expected, pat_ty); // Type check subpatterns. @@ -644,7 +640,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { variant.fields.len(), fields_ending, subpats.len())) .emit(); on_error(); + return tcx.types.err; } + pat_ty } fn check_struct_pat_fields(&self, From bd661481e79bb5701455b03d8d3b587309e56186 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Sat, 27 Aug 2016 20:38:06 +0800 Subject: [PATCH 17/20] Move write_ty to the bottom of check_pat --- src/librustc_typeck/check/_match.rs | 37 ++++++++++++++--------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index ee66597e72a46..c1a0a6f70aa44 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -32,9 +32,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("check_pat(pat={:?},expected={:?})", pat, expected); - match pat.node { + let ty = match pat.node { PatKind::Wild => { - self.write_ty(pat.id, expected); + expected } PatKind::Lit(ref lt) => { let ty = self.check_expr(<); @@ -67,7 +67,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // // that's equivalent to there existing a LUB. self.demand_suptype(pat.span, expected, pat_ty); - self.write_ty(pat.id, pat_ty); + pat_ty } PatKind::Range(ref begin, ref end) => { let lhs_ty = self.check_expr(begin); @@ -103,7 +103,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // subtyping doesn't matter here, as the value is some kind of scalar self.demand_eqtype(pat.span, expected, lhs_ty); self.demand_eqtype(pat.span, expected, rhs_ty); - self.write_ty(pat.id, common_type); + common_type } PatKind::Binding(bm, _, ref sub) => { let typ = self.local_ty(pat.span, pat.id); @@ -147,20 +147,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_pat(&p, expected); } - self.write_ty(pat.id, typ); + typ } PatKind::TupleStruct(ref path, ref subpats, ddpos) => { - let pat_ty = self.check_pat_tuple_struct(pat, path, &subpats, ddpos, expected); - write_ty(pat.id, pat_ty); + self.check_pat_tuple_struct(pat, path, &subpats, ddpos, expected) } PatKind::Path(ref opt_qself, ref path) => { let opt_qself_ty = opt_qself.as_ref().map(|qself| self.to_ty(&qself.ty)); - let pat_ty = self.check_pat_path(pat, opt_qself_ty, path, expected); - write_ty(pat.id, pat_ty); + self.check_pat_path(pat, opt_qself_ty, path, expected) } PatKind::Struct(ref path, ref fields, etc) => { - let pat_ty = self.check_pat_struct(pat, path, fields, etc, expected); - write_ty(pat.id, pat_ty); + self.check_pat_struct(pat, path, fields, etc, expected) } PatKind::Tuple(ref elements, ddpos) => { let mut expected_len = elements.len(); @@ -179,7 +176,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { self.check_pat(elem, &element_tys[i]); } - self.write_ty(pat.id, pat_ty); + pat_ty } PatKind::Box(ref inner) => { let inner_ty = self.next_ty_var(); @@ -191,10 +188,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // `demand::eqtype`. self.demand_eqtype(pat.span, expected, uniq_ty); self.check_pat(&inner, inner_ty); - self.write_ty(pat.id, uniq_ty); + uniq_ty } else { self.check_pat(&inner, tcx.types.err); - self.write_error(pat.id); + tcx.types.err } } PatKind::Ref(ref inner, mutbl) => { @@ -223,10 +220,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; self.check_pat(&inner, inner_ty); - self.write_ty(pat.id, rptr_ty); + rptr_ty } else { self.check_pat(&inner, tcx.types.err); - self.write_error(pat.id); + tcx.types.err } } PatKind::Vec(ref before, ref slice, ref after) => { @@ -287,9 +284,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { for elt in after { self.check_pat(&elt, inner_ty); } - self.write_ty(pat.id, expected_ty); + expected_ty } - } + }; + + self.write_ty(pat.id, ty); // (*) In most of the cases above (literals and constants being // the exception), we relate types using strict equality, evewn @@ -494,7 +493,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { for field in fields { self.check_pat(&field.node.pat, self.tcx.types.err); } - return tcx.types.err; + return self.tcx.types.err; }; // Type check the path. From 180534f398b18aea5d7740153eab026074396013 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Sun, 28 Aug 2016 16:17:52 +0800 Subject: [PATCH 18/20] Remove use of expr_ty from coercions code --- src/librustc_typeck/check/_match.rs | 10 +++++++--- src/librustc_typeck/check/cast.rs | 4 ++-- src/librustc_typeck/check/coercion.rs | 22 +++++++++++++--------- src/librustc_typeck/check/demand.rs | 6 +++--- src/librustc_typeck/check/mod.rs | 21 ++++++++++++--------- 5 files changed, 37 insertions(+), 26 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index c1a0a6f70aa44..42769a8636407 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -419,11 +419,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } _ => result_ty }; + + let mut arm_tys = Vec::new(); for (i, arm) in arms.iter().enumerate() { if let Some(ref e) = arm.guard { self.check_expr_has_type(e, tcx.types.bool); } let arm_ty = self.check_expr_with_expectation(&arm.body, expected); + arm_tys.push(arm_ty); if result_ty.references_error() || arm_ty.references_error() { result_ty = tcx.types.err; @@ -453,10 +456,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }) } else if i == 0 { // Special-case the first arm, as it has no "previous expressions". - self.try_coerce(&arm.body, coerce_first) + self.try_coerce(&arm.body, arm_ty, 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) + let prev_arms = || arms[..i].iter().map(|arm| &*arm.body) + .zip(arm_tys.iter().cloned()); + self.try_find_coercion_lub(origin, prev_arms, result_ty, &arm.body, arm_ty) }; result_ty = match result { diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 1fda38d8a3305..0c9da86563ab2 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -321,7 +321,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { (None, Some(t_cast)) => { if let ty::TyFnDef(.., f) = self.expr_ty.sty { // Attempt a coercion to a fn pointer type. - let res = fcx.try_coerce(self.expr, fcx.tcx.mk_fn_ptr(f)); + let res = fcx.try_coerce(self.expr, self.expr_ty, fcx.tcx.mk_fn_ptr(f)); if !res.is_ok() { return Err(CastError::NonScalar); } @@ -471,7 +471,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> bool { - fcx.try_coerce(self.expr, self.cast_ty).is_ok() + fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty).is_ok() } } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 60ca9309eea00..263a83389ea9d 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -630,9 +630,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// The expressions *must not* have any pre-existing adjustments. pub fn try_coerce(&self, expr: &hir::Expr, + expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - let source = self.resolve_type_vars_with_obligations(self.expr_ty(expr)); + let source = self.resolve_type_vars_with_obligations(expr_ty); debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target); let mut coerce = Coerce::new(self, TypeOrigin::ExprAssignable(expr.span)); @@ -658,14 +659,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { origin: TypeOrigin, exprs: E, prev_ty: Ty<'tcx>, - new: &'b hir::Expr) + new: &'b hir::Expr, + new_ty: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> // FIXME(eddyb) use copyable iterators when that becomes ergonomic. where E: Fn() -> I, - I: IntoIterator { + 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)); + let new_ty = self.resolve_type_vars_with_obligations(new_ty); debug!("coercion::try_find_lub({:?}, {:?})", prev_ty, new_ty); let trace = TypeTrace::types(origin, true, prev_ty, new_ty); @@ -701,7 +703,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } // Reify both sides and return the reified fn pointer type. - for expr in exprs().into_iter().chain(Some(new)) { + for (expr, _) in exprs().into_iter().chain(Some((new, new_ty))) { // 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); @@ -735,13 +737,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // 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() { + for (expr, expr_ty) 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 { + })) => match expr_ty.sty { ty::TyRef(_, mt_orig) => { // Reborrow that we can safely ignore. mutbl_adj == mt_orig.mutbl @@ -765,7 +767,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - match self.commit_if_ok(|_| apply(&mut coerce, &exprs, prev_ty, new_ty)) { + match self.commit_if_ok(|_| apply(&mut coerce, + &|| exprs().into_iter().map(|(e, _)| e), + prev_ty, new_ty)) { Err(_) => { // Avoid giving strange errors on failed attempts. if let Some(e) = first_error { @@ -783,7 +787,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } Ok((ty, adjustment)) => { if !adjustment.is_identity() { - for expr in exprs() { + for (expr, _) in exprs() { let previous = self.tables.borrow().adjustments.get(&expr.id).cloned(); if let Some(AdjustNeverToAny(_)) = previous { self.write_adjustment(expr.id, AdjustNeverToAny(ty)); diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 1f3a83ebc1d56..d622bc7f751d7 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -53,11 +53,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } // Checks that the type of `expr` can be coerced to `expected`. - pub fn demand_coerce(&self, expr: &hir::Expr, expected: Ty<'tcx>) { + pub fn demand_coerce(&self, expr: &hir::Expr, checked_ty: Ty<'tcx>, expected: Ty<'tcx>) { let expected = self.resolve_type_vars_with_obligations(expected); - if let Err(e) = self.try_coerce(expr, expected) { + if let Err(e) = self.try_coerce(expr, checked_ty, expected) { let origin = TypeOrigin::Misc(expr.span); - let expr_ty = self.resolve_type_vars_with_obligations(self.expr_ty(expr)); + let expr_ty = self.resolve_type_vars_with_obligations(checked_ty); self.report_mismatched_types(origin, expected, expr_ty, e); } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 79dd951a5d85e..b128333921356 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2567,13 +2567,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Expectation::rvalue_hint(self, ty) }); - self.check_expr_with_expectation(&arg, - expected.unwrap_or(ExpectHasType(formal_ty))); + let checked_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)); + self.demand_coerce(&arg, checked_ty, coerce_ty.unwrap_or(formal_ty)); // 3. Relate the expected type and the formal one, // if the expected type was used for the coercion. @@ -2715,7 +2715,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr: &'gcx hir::Expr, expected: Ty<'tcx>) -> Ty<'tcx> { let ty = self.check_expr_with_hint(expr, expected); - self.demand_coerce(expr, expected); + self.demand_coerce(expr, ty, expected); ty } @@ -2861,8 +2861,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Only try to coerce-unify if we have a then expression // to assign coercions to, otherwise it's () or diverging. let result = if let Some(ref then) = then_blk.expr { - let res = self.try_find_coercion_lub(origin, || Some(&**then), - then_ty, else_expr); + let res = self.try_find_coercion_lub(origin, || Some((&**then, then_ty)), + then_ty, else_expr, else_ty); // In case we did perform an adjustment, we have to update // the type of the block, because old trans still uses it. @@ -3594,16 +3594,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut unified = self.next_ty_var(); let coerce_to = uty.unwrap_or(unified); + let mut arg_tys = Vec::new(); for (i, e) in args.iter().enumerate() { let e_ty = self.check_expr_with_hint(e, coerce_to); + arg_tys.push(e_ty); 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) + self.try_coerce(e, e_ty, coerce_to) } else { - let prev_elems = || args[..i].iter().map(|e| &**e); - self.try_find_coercion_lub(origin, prev_elems, unified, e) + let prev_elems = || args[..i].iter().map(|e| &**e) + .zip(arg_tys.iter().cloned()); + self.try_find_coercion_lub(origin, prev_elems, unified, e, e_ty) }; match result { From 7c8f5457d26055b26210fdd69c5ded1ecdde144a Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Sun, 28 Aug 2016 17:29:54 +0800 Subject: [PATCH 19/20] Undo unnecessary bookkeeping from last commit --- src/librustc_typeck/check/_match.rs | 5 +---- src/librustc_typeck/check/coercion.rs | 14 ++++++-------- src/librustc_typeck/check/mod.rs | 7 ++----- 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 42769a8636407..c67b98761aa6e 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -420,13 +420,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => result_ty }; - let mut arm_tys = Vec::new(); for (i, arm) in arms.iter().enumerate() { if let Some(ref e) = arm.guard { self.check_expr_has_type(e, tcx.types.bool); } let arm_ty = self.check_expr_with_expectation(&arm.body, expected); - arm_tys.push(arm_ty); if result_ty.references_error() || arm_ty.references_error() { result_ty = tcx.types.err; @@ -458,8 +456,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Special-case the first arm, as it has no "previous expressions". self.try_coerce(&arm.body, arm_ty, coerce_first) } else { - let prev_arms = || arms[..i].iter().map(|arm| &*arm.body) - .zip(arm_tys.iter().cloned()); + let prev_arms = || arms[..i].iter().map(|arm| &*arm.body); self.try_find_coercion_lub(origin, prev_arms, result_ty, &arm.body, arm_ty) }; diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 263a83389ea9d..98a05989b140d 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -664,7 +664,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { -> RelateResult<'tcx, Ty<'tcx>> // FIXME(eddyb) use copyable iterators when that becomes ergonomic. where E: Fn() -> I, - I: IntoIterator)> { + I: IntoIterator { let prev_ty = self.resolve_type_vars_with_obligations(prev_ty); let new_ty = self.resolve_type_vars_with_obligations(new_ty); @@ -703,7 +703,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } // Reify both sides and return the reified fn pointer type. - for (expr, _) in exprs().into_iter().chain(Some((new, new_ty))) { + 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); @@ -737,13 +737,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // 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, expr_ty) in exprs() { + 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 expr_ty.sty { + })) => match self.node_ty(expr.id).sty { ty::TyRef(_, mt_orig) => { // Reborrow that we can safely ignore. mutbl_adj == mt_orig.mutbl @@ -767,9 +767,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - match self.commit_if_ok(|_| apply(&mut coerce, - &|| exprs().into_iter().map(|(e, _)| e), - prev_ty, new_ty)) { + 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 { @@ -787,7 +785,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } Ok((ty, adjustment)) => { if !adjustment.is_identity() { - for (expr, _) in exprs() { + for expr in exprs() { let previous = self.tables.borrow().adjustments.get(&expr.id).cloned(); if let Some(AdjustNeverToAny(_)) = previous { self.write_adjustment(expr.id, AdjustNeverToAny(ty)); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index b128333921356..1e57cc5d6c847 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2861,7 +2861,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Only try to coerce-unify if we have a then expression // to assign coercions to, otherwise it's () or diverging. let result = if let Some(ref then) = then_blk.expr { - let res = self.try_find_coercion_lub(origin, || Some((&**then, then_ty)), + let res = self.try_find_coercion_lub(origin, || Some(&**then), then_ty, else_expr, else_ty); // In case we did perform an adjustment, we have to update @@ -3594,18 +3594,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut unified = self.next_ty_var(); let coerce_to = uty.unwrap_or(unified); - let mut arg_tys = Vec::new(); for (i, e) in args.iter().enumerate() { let e_ty = self.check_expr_with_hint(e, coerce_to); - arg_tys.push(e_ty); 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, e_ty, coerce_to) } else { - let prev_elems = || args[..i].iter().map(|e| &**e) - .zip(arg_tys.iter().cloned()); + let prev_elems = || args[..i].iter().map(|e| &**e); self.try_find_coercion_lub(origin, prev_elems, unified, e, e_ty) }; From c9a340e546ac2c708d6f334a83cfbf6a38810255 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Sun, 28 Aug 2016 19:37:57 +0800 Subject: [PATCH 20/20] Remove expr_ty method completely --- src/librustc_typeck/check/method/confirm.rs | 8 ++++---- src/librustc_typeck/check/mod.rs | 13 ------------- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index dbf74e371df45..ab59fafb65209 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -472,7 +472,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { i, expr, autoderef_count); if autoderef_count > 0 { - let mut autoderef = self.autoderef(expr.span, self.expr_ty(expr)); + let mut autoderef = self.autoderef(expr.span, self.node_ty(expr.id)); autoderef.nth(autoderef_count).unwrap_or_else(|| { span_bug!(expr.span, "expr was deref-able {} times but now isn't?", autoderef_count); @@ -532,7 +532,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { unsize: None }))), false) }; - let index_expr_ty = self.expr_ty(&index_expr); + let index_expr_ty = self.node_ty(index_expr.id); let result = self.try_index_step( ty::MethodCall::expr(expr.id), @@ -547,7 +547,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { if let Some((input_ty, return_ty)) = result { self.demand_suptype(index_expr.span, input_ty, index_expr_ty); - let expr_ty = self.expr_ty(&expr); + let expr_ty = self.node_ty(expr.id); self.demand_suptype(expr.span, expr_ty, return_ty); } } @@ -558,7 +558,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { if self.tables.borrow().method_map.contains_key(&method_call) { let method = self.try_overloaded_deref(expr.span, Some(&base_expr), - self.expr_ty(&base_expr), + self.node_ty(base_expr.id), PreferMutLvalue); let method = method.expect("re-trying deref failed"); self.tables.borrow_mut().method_map.insert(method_call, method); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 1e57cc5d6c847..00fdcd59f7cee 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1763,19 +1763,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { t } - pub fn expr_ty(&self, ex: &hir::Expr) -> Ty<'tcx> { - if let Some(&adjustment::AdjustNeverToAny(ref t)) - = self.tables.borrow().adjustments.get(&ex.id) { - return t; - } - match self.tables.borrow().node_types.get(&ex.id) { - Some(&t) => t, - None => { - bug!("no type for expr in fcx {}", self.tag()); - } - } - } - /// Apply `adjustment` to the type of `expr` pub fn adjust_expr_ty(&self, expr: &hir::Expr,