diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 12fce4b928e08..c67b98761aa6e 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -32,17 +32,16 @@ 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) => { - self.check_expr(<); - let expr_ty = self.expr_ty(<); + 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_ty; + 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); @@ -55,28 +54,24 @@ 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 // 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 `ty` is // type is `&'static str`, so if we say that // // &'static str <: expected // // that's equivalent to there existing a LUB. self.demand_suptype(pat.span, expected, pat_ty); + 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(); @@ -105,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); + common_type } PatKind::Binding(bm, _, ref sub) => { let typ = self.local_ty(pat.span, pat.id); @@ -136,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) { @@ -154,16 +146,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(ref p) = *sub { self.check_pat(&p, expected); } + + typ } PatKind::TupleStruct(ref path, ref subpats, ddpos) => { - self.check_pat_tuple_struct(pat, path, &subpats, ddpos, expected); + 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)); - self.check_pat_path(pat, opt_qself_ty, path, expected); + self.check_pat_path(pat, opt_qself_ty, path, expected) } PatKind::Struct(ref path, ref fields, etc) => { - self.check_pat_struct(pat, path, fields, etc, expected); + self.check_pat_struct(pat, path, fields, etc, expected) } PatKind::Tuple(ref elements, ddpos) => { let mut expected_len = elements.len(); @@ -178,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]); } + pat_ty } PatKind::Box(ref inner) => { let inner_ty = self.next_ty_var(); @@ -193,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); + uniq_ty } else { - self.write_error(pat.id); self.check_pat(&inner, tcx.types.err); + tcx.types.err } } PatKind::Ref(ref inner, mutbl) => { @@ -225,11 +219,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; - self.write_ty(pat.id, rptr_ty); self.check_pat(&inner, inner_ty); + rptr_ty } else { - self.write_error(pat.id); self.check_pat(&inner, tcx.types.err); + tcx.types.err } } PatKind::Vec(ref before, ref slice, ref after) => { @@ -281,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); } @@ -292,8 +284,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { for elt in after { self.check_pat(&elt, inner_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 @@ -371,7 +366,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 @@ -385,8 +380,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 @@ -425,12 +419,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } _ => result_ty }; + for (i, arm) in arms.iter().enumerate() { if let Some(ref e) = arm.guard { self.check_expr_has_type(e, tcx.types.bool); } - self.check_expr_with_expectation(&arm.body, expected); - let arm_ty = self.expr_ty(&arm.body); + 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; @@ -460,10 +454,10 @@ 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) + self.try_find_coercion_lub(origin, prev_arms, result_ty, &arm.body, arm_ty) }; result_ty = match result { @@ -480,7 +474,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; } - self.write_ty(expr.id, result_ty); + result_ty } } @@ -490,18 +484,17 @@ 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 self.tcx.types.err; }; // Type check the path. @@ -509,20 +502,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // 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. @@ -531,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 @@ -552,6 +544,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.demand_suptype(pat.span, expected, pat_ty); + pat_ty } fn check_pat_tuple_struct(&self, @@ -559,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); } @@ -587,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) @@ -604,12 +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); - 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() @@ -617,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. @@ -650,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, diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 49db56d2dabd9..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; @@ -45,10 +45,9 @@ 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); + 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)| { @@ -57,25 +56,30 @@ 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); + 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) } - } + }; + + // 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, @@ -181,7 +185,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 +249,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn_sig.variadic, TupleArgumentsFlag::DontTupleArguments); - self.write_call(call_expr, fn_sig.output); + 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 +276,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn_sig.variadic, TupleArgumentsFlag::TupleArguments); - self.write_call(call_expr, fn_sig.output); + fn_sig.output } fn confirm_overloaded_call(&self, @@ -280,7 +284,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 +293,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { arg_exprs, TupleArgumentsFlag::TupleArguments, expected); - self.write_call(call_expr, output_type); self.write_overloaded_call_method_map(call_expr, method_callee); + output_type } fn write_overloaded_call_method_map(&self, 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/closure.rs b/src/librustc_typeck/check/closure.rs index 8980cb9076027..9e41d1b5676e4 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,8 +70,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.parameter_environment.free_substs, upvar_tys); - self.write_ty(expr.id, closure_type); - let fn_sig = self.tcx.liberate_late_bound_regions( self.tcx.region_maps.call_site_extent(expr.id, body.id), &fn_ty.sig); let fn_sig = @@ -93,6 +91,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Some(kind) => { self.tables.borrow_mut().closure_kinds.insert(expr_def_id, kind); } None => { } } + + closure_type } fn deduce_expectations_from_expected_type(&self, expected_ty: Ty<'tcx>) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 60ca9309eea00..98a05989b140d 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 { 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); @@ -741,7 +743,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { autoderefs: 1, autoref: Some(AutoPtr(_, mutbl_adj)), unsize: None - })) => match self.expr_ty(expr).sty { + })) => match self.node_ty(expr.id).sty { ty::TyRef(_, mt_orig) => { // Reborrow that we can safely ignore. mutbl_adj == mt_orig.mutbl 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/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 0aa523e9d5e47..00fdcd59f7cee 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1534,14 +1534,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, '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 = adjustment::AdjustNeverToAny(self.next_diverging_ty_var()); - self.write_adjustment(node_id, adj); - } - } } pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) { @@ -1708,7 +1700,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 }); @@ -1747,13 +1738,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, @@ -1779,26 +1763,13 @@ 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, 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| { @@ -2583,13 +2554,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. @@ -2620,12 +2591,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| { @@ -2666,12 +2637,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, @@ -2721,41 +2686,43 @@ 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>) { - self.check_expr_with_hint(expr, expected); - self.demand_suptype(expr.span, expected, self.expr_ty(expr)); + expected: Ty<'tcx>) -> Ty<'tcx> { + let ty = self.check_expr_with_hint(expr, expected); + self.demand_suptype(expr.span, expected, ty); + ty } fn check_expr_coercable_to_type(&self, expr: &'gcx hir::Expr, - expected: Ty<'tcx>) { - self.check_expr_with_hint(expr, expected); - self.demand_coerce(expr, expected); + expected: Ty<'tcx>) -> Ty<'tcx> { + let ty = self.check_expr_with_hint(expr, expected); + self.demand_coerce(expr, ty, 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,12 +2787,12 @@ 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); + 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, @@ -2856,7 +2823,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { DontTupleArguments, expected); - self.write_call(expr, ret_ty); + ret_ty } // A generic function for checking the then and else in an if @@ -2865,27 +2832,24 @@ 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>) { - self.check_expr_has_type(cond_expr, self.tcx.types.bool); + expected: Expectation<'tcx>) -> Ty<'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) = 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 // 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); + 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. @@ -2918,9 +2882,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { })) }; - let if_ty = match result { + match result { Ok(ty) => { - if self.expr_ty(cond_expr).references_error() { + if cond_ty.references_error() { self.tcx.types.err } else { ty @@ -2930,9 +2894,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 @@ -2940,10 +2902,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr: &'gcx hir::Expr, lvalue_pref: LvaluePreference, base: &'gcx hir::Expr, - field: &Spanned) { - self.check_expr_with_lvalue_pref(base, lvalue_pref); + field: &Spanned) -> Ty<'tcx> { + 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() { @@ -2954,9 +2916,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)); - self.write_ty(expr.id, field_ty); self.write_autoderef_adjustment(base.id, autoderefs); - return; + return field_ty; } private_candidate = Some((base_def.did, field_ty)); } @@ -2968,7 +2929,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); - 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 +2937,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { field.node)); } err.emit(); + 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 \ @@ -2987,7 +2948,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 `{}`, \ @@ -3005,7 +2966,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => {} } err.emit(); - self.write_error(expr.id); + self.tcx().types.err } } @@ -3037,10 +2998,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr: &'gcx hir::Expr, lvalue_pref: LvaluePreference, base: &'gcx hir::Expr, - idx: codemap::Spanned) { - self.check_expr_with_lvalue_pref(base, lvalue_pref); + idx: codemap::Spanned) -> Ty<'tcx> { + 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); @@ -3070,9 +3031,8 @@ 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); self.write_autoderef_adjustment(base.id, autoderefs); - return; + return field_ty; } } autoderef.unambiguous_final_ty(); @@ -3081,8 +3041,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 field_ty; } self.type_error_message( @@ -3102,7 +3061,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, @@ -3205,17 +3164,15 @@ 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>) { - // Make sure to still write the types - // otherwise we might ICE - 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 => {} } } @@ -3267,22 +3224,22 @@ 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) { + 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(expr.id, fields, base_expr); - return; + self.check_struct_fields_on_error(fields, base_expr); + return self.tcx().types.err; }; - self.check_expr_struct_fields(expr_ty, 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_ty); - match expr_ty.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, @@ -3299,6 +3256,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } } + self.require_type_is_sized(struct_ty, expr.span, traits::StructInitializerSized); + struct_ty } @@ -3315,10 +3274,35 @@ 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 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; match expr.node { @@ -3329,20 +3313,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => NoExpectation } }); - self.check_expr_with_expectation(subexpr, expected_inner); - let referent_ty = self.expr_ty(&subexpr); - self.write_ty(id, tcx.mk_box(referent_ty)); + let referent_ty = self.check_expr_with_expectation(subexpr, expected_inner); + 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) => { - 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 +3339,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 +3383,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| { @@ -3421,10 +3402,10 @@ 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 oprnd_t = if tm.ty.references_error() { + let tm = ty::TypeAndMut { ty: ty, mutbl: mutbl }; + if tm.ty.references_error() { tcx.types.err } else { // Note: at this point, we cannot say what the best lifetime @@ -3442,25 +3423,26 @@ 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)); 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); - } + tcx.types.err + }; // We always require that the type provided as the value for // a type parameter outlives the moment of instantiation. self.opt_node_ty_substs(expr.id, |item_substs| { self.add_wf_bounds(&item_substs.substs, expr); }); + + ty } hir::ExprInlineAsm(_, ref outputs, ref inputs) => { for output in outputs { @@ -3469,10 +3451,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); @@ -3490,10 +3472,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .emit(); } } - self.write_never(id); + tcx.types.never } 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,66 +3488,53 @@ 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); + 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) => { self.check_then_else(&cond, &then_blk, opt_else_expr.as_ref().map(|e| &**e), - id, expr.span, expected); + 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); + 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) => { - 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)); + self.check_block_with_expected(&b, expected) } hir::ExprCall(ref callee, ref args) => { - self.check_call(expr, &callee, &args[..], expected); - - // we must check that return type of called functions is WF: - let ret_ty = self.expr_ty(expr); - self.register_wf_obligation(ret_ty, expr.span, traits::MiscObligation); + self.check_call(expr, &callee, &args[..], expected) } hir::ExprMethodCall(name, ref tps, ref args) => { - self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref); - let arg_tys = args.iter().map(|a| self.expr_ty(&a)); - let args_err = arg_tys.fold(false, |rest_err, a| rest_err || a.references_error()); - if args_err { - self.write_error(id); - } + 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 { @@ -3576,26 +3545,22 @@ 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); + tcx.types.err } else { - // Write a type for the whole expression, assuming everything is going - // to work out Ok. - self.write_ty(id, t_cast); - // Defer other checks until we're done type checking. let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) { Ok(cast_check) => { deferred_cast_checks.push(cast_check); + t_cast } Err(ErrorReported) => { - self.write_error(id); + tcx.types.err } } } @@ -3603,7 +3568,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| { @@ -3617,16 +3582,15 @@ 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". 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) + self.try_find_coercion_lub(origin, prev_elems, unified, e, e_ty) }; match result { @@ -3636,7 +3600,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); @@ -3660,8 +3624,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 +3636,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) => { @@ -3695,49 +3658,41 @@ 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); + 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) => { - self.check_expr_struct(expr, path, fields, base_expr); - - self.require_expr_have_sized_type(expr, traits::StructInitializerSized); + self.check_expr_struct(expr, path, fields, base_expr) } 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); + 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)) => { - 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.demand_eqtype(expr.span, index_ty, idx_t); + element_ty } None => { self.check_expr_has_type(&idx, self.tcx.types.err); @@ -3773,18 +3728,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } err.emit(); - self.write_ty(id, self.tcx().types.err); + self.tcx().types.err } } } } } - - debug!("type of expr({}) {} is...", expr.id, - pprust::expr_to_string(expr)); - debug!("... {:?}, expected is {:?}", - self.expr_ty(expr), - expected); } // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary. @@ -3864,7 +3813,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); @@ -3878,12 +3827,12 @@ 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) - }; + } } pub fn check_decl_local(&self, local: &'gcx hir::Local) { @@ -3891,8 +3840,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); } @@ -3905,7 +3853,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; @@ -3925,17 +3873,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 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; - 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 ty = self.check_expr(&expr); + saw_bot |= self.type_var_diverges(ty); + saw_err |= ty.references_error(); } } if saw_bot { @@ -3945,13 +3891,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.write_error(node_id); } else { - self.write_nil(node_id) + self.write_nil(node_id); } } pub fn check_block_no_value(&self, blk: &'gcx hir::Block) { - self.check_block_with_expected(blk, ExpectHasType(self.tcx.mk_nil())); - let blkty = self.node_ty(blk.id); + let blkty = self.check_block_with_expected(blk, ExpectHasType(self.tcx.mk_nil())); if blkty.references_error() { self.write_error(blk.id); } else { @@ -3962,7 +3907,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); @@ -3999,13 +3944,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 { @@ -4022,22 +3967,23 @@ 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) } }; 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 @@ -4348,7 +4294,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 }); diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index a8b1683f6d354..411bd7e7b5ca1 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -23,21 +23,22 @@ 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); + 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); - 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 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; @@ -67,15 +69,15 @@ 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); 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,7 +109,7 @@ 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 } } }