Skip to content

Commit

Permalink
Propagate expected type hints through struct literals.
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyb committed Mar 9, 2017
1 parent c7db40f commit 50aee36
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 8 deletions.
29 changes: 21 additions & 8 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")
};

Expand All @@ -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);

Expand All @@ -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,
Expand All @@ -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.
Expand Down Expand Up @@ -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<P<hir::Expr>>) -> Ty<'tcx>
Expand All @@ -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);
Expand Down Expand Up @@ -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)
Expand Down
20 changes: 20 additions & 0 deletions src/test/run-pass/issue-31260.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

pub struct Struct<K: 'static> {
pub field: K,
}

// Partial fix for #31260, doesn't work without {...}.
static STRUCT: Struct<&'static [u8]> = Struct {
field: {&[1]}
};

fn main() {}

0 comments on commit 50aee36

Please sign in to comment.