diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 4b88f5acf42da..529ee107c46ce 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -254,7 +254,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Call the generic checker. let expected_arg_tys = - self.expected_types_for_fn_args(call_expr.span, + self.expected_inputs_for_expected_output(call_expr.span, expected, fn_sig.output(), fn_sig.inputs()); @@ -280,7 +280,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // do know the types expected for each argument and the return // type. - let expected_arg_tys = self.expected_types_for_fn_args(call_expr.span, + let expected_arg_tys = self.expected_inputs_for_expected_output(call_expr.span, expected, fn_sig.output().clone(), fn_sig.inputs()); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e8957bad0986c..f43dcefb84591 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2321,7 +2321,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match method_fn_ty.sty { ty::TyFnDef(def_id, .., ref fty) => { // HACK(eddyb) ignore self in the definition (see above). - let expected_arg_tys = self.expected_types_for_fn_args( + let expected_arg_tys = self.expected_inputs_for_expected_output( sp, expected, fty.0.output(), @@ -2674,14 +2674,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { TypeAndSubsts { substs: substs, ty: substd_ty } } - /// Unifies the return type with the expected type early, for more coercions - /// and forward type information on the argument expressions. - fn expected_types_for_fn_args(&self, - call_span: Span, - expected_ret: Expectation<'tcx>, - formal_ret: Ty<'tcx>, - formal_args: &[Ty<'tcx>]) - -> Vec> { + /// Unifies the output type with the expected type early, for more coercions + /// and forward type information on the input expressions. + fn expected_inputs_for_expected_output(&self, + call_span: Span, + expected_ret: Expectation<'tcx>, + formal_ret: Ty<'tcx>, + formal_args: &[Ty<'tcx>]) + -> Vec> { let expected_args = expected_ret.only_has_type(self).and_then(|ret_ty| { self.fudge_regions_if_ok(&RegionVariableOrigin::Coercion(call_span), || { // Attempt to apply a subtyping relationship between the formal @@ -2704,7 +2704,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }).collect()) }).ok() }).unwrap_or(vec![]); - debug!("expected_types_for_fn_args(formal={:?} -> {:?}, expected={:?} -> {:?})", + debug!("expected_inputs_for_expected_output(formal={:?} -> {:?}, expected={:?} -> {:?})", formal_args, formal_ret, expected_args, expected_ret); expected_args @@ -3061,14 +3061,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn check_expr_struct_fields(&self, adt_ty: Ty<'tcx>, + expected: Expectation<'tcx>, expr_id: ast::NodeId, span: Span, variant: &'tcx ty::VariantDef, ast_fields: &'gcx [hir::Field], check_completeness: bool) { let tcx = self.tcx; - let (substs, adt_kind, kind_name) = match adt_ty.sty { - ty::TyAdt(adt, substs) => (substs, adt.adt_kind(), adt.variant_descr()), + + let adt_ty_hint = + self.expected_inputs_for_expected_output(span, expected, adt_ty, &[adt_ty]) + .get(0).cloned().unwrap_or(adt_ty); + + let (substs, hint_substs, adt_kind, kind_name) = match (&adt_ty.sty, &adt_ty_hint.sty) { + (&ty::TyAdt(adt, substs), &ty::TyAdt(_, hint_substs)) => { + (substs, hint_substs, adt.adt_kind(), adt.variant_descr()) + } _ => span_bug!(span, "non-ADT passed to check_expr_struct_fields") }; @@ -3083,10 +3091,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Typecheck each field. for field in ast_fields { - let expected_field_type; + let final_field_type; + let field_type_hint; if let Some(v_field) = remaining_fields.remove(&field.name.node) { - expected_field_type = self.field_ty(field.span, v_field, substs); + final_field_type = self.field_ty(field.span, v_field, substs); + field_type_hint = self.field_ty(field.span, v_field, hint_substs); seen_fields.insert(field.name.node, field.span); @@ -3098,7 +3108,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } else { error_happened = true; - expected_field_type = tcx.types.err; + final_field_type = tcx.types.err; + field_type_hint = tcx.types.err; if let Some(_) = variant.find_field_named(field.name.node) { let mut err = struct_span_err!(self.tcx.sess, field.name.span, @@ -3120,7 +3131,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Make sure to give a type to the field even if there's // an error, so we can continue typechecking - self.check_expr_coercable_to_type(&field.expr, expected_field_type); + let ty = self.check_expr_with_hint(&field.expr, field_type_hint); + self.demand_coerce(&field.expr, ty, final_field_type); } // Make sure the programmer specified correct number of fields. @@ -3230,6 +3242,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn check_expr_struct(&self, expr: &hir::Expr, + expected: Expectation<'tcx>, qpath: &hir::QPath, fields: &'gcx [hir::Field], base_expr: &'gcx Option>) -> Ty<'tcx> @@ -3248,7 +3261,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::QPath::TypeRelative(ref qself, _) => qself.span }; - self.check_expr_struct_fields(struct_ty, expr.id, path_span, variant, fields, + self.check_expr_struct_fields(struct_ty, expected, expr.id, path_span, variant, fields, base_expr.is_none()); if let &Some(ref base_expr) = base_expr { self.check_expr_has_type(base_expr, struct_ty); @@ -3793,7 +3806,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } hir::ExprStruct(ref qpath, ref fields, ref base_expr) => { - self.check_expr_struct(expr, qpath, fields, base_expr) + self.check_expr_struct(expr, expected, qpath, fields, base_expr) } hir::ExprField(ref base, ref field) => { self.check_field(expr, lvalue_pref, &base, field) diff --git a/src/test/run-pass/issue-31260.rs b/src/test/run-pass/issue-31260.rs new file mode 100644 index 0000000000000..e771fc7464d00 --- /dev/null +++ b/src/test/run-pass/issue-31260.rs @@ -0,0 +1,20 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub struct Struct { + pub field: K, +} + +// Partial fix for #31260, doesn't work without {...}. +static STRUCT: Struct<&'static [u8]> = Struct { + field: {&[1]} +}; + +fn main() {}