提交 cb98c3d9 编写于 作者: N Niko Matsakis

Normalize types of fields in struct literals during type-checking.

Fixes #20535.
上级 18f426e6
......@@ -52,7 +52,6 @@
use middle::def;
use middle::resolve_lifetime as rl;
use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
use middle::subst::{VecPerParamSpace};
use middle::traits;
use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
use rscope::{self, UnelidableRscope, RegionScope, SpecificRscope,
......@@ -244,7 +243,7 @@ pub fn opt_ast_region_to_region<'tcx>(
/// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`,
/// returns an appropriate set of substitutions for this particular reference to `I`.
fn ast_path_substs_for_ty<'tcx>(
pub fn ast_path_substs_for_ty<'tcx>(
this: &AstConv<'tcx>,
rscope: &RegionScope,
decl_generics: &ty::Generics<'tcx>,
......@@ -762,50 +761,6 @@ pub fn ast_path_to_ty<'tcx>(
TypeAndSubsts { substs: substs, ty: ty }
}
/// Returns the type that this AST path refers to. If the path has no type
/// parameters and the corresponding type has type parameters, fresh type
/// and/or region variables are substituted.
///
/// This is used when checking the constructor in struct literals.
pub fn ast_path_to_ty_relaxed<'tcx>(
this: &AstConv<'tcx>,
rscope: &RegionScope,
did: ast::DefId,
path: &ast::Path)
-> TypeAndSubsts<'tcx>
{
let tcx = this.tcx();
let ty::TypeScheme {
generics,
ty: decl_ty
} = this.get_item_type_scheme(did);
let wants_params =
generics.has_type_params(TypeSpace) || generics.has_region_params(TypeSpace);
let needs_defaults =
wants_params &&
path.segments.iter().all(|s| s.parameters.is_empty());
let substs = if needs_defaults {
let type_params: Vec<_> = range(0, generics.types.len(TypeSpace))
.map(|_| this.ty_infer(path.span)).collect();
let region_params =
rscope.anon_regions(path.span, generics.regions.len(TypeSpace))
.unwrap();
Substs::new(VecPerParamSpace::params_from_type(type_params),
VecPerParamSpace::params_from_type(region_params))
} else {
ast_path_substs_for_ty(this, rscope, &generics, path)
};
let ty = decl_ty.subst(tcx, &substs);
TypeAndSubsts {
substs: substs,
ty: ty,
}
}
/// Converts the given AST type to a built-in type. A "built-in type" is, at
/// present, either a core numeric type, a string, or `Box`.
pub fn ast_ty_to_builtin_ty<'tcx>(
......
......@@ -90,7 +90,7 @@
use middle::mem_categorization::McResult;
use middle::pat_util::{self, pat_id_map};
use middle::region::CodeExtent;
use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace};
use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace, TypeSpace};
use middle::traits;
use middle::ty::{FnSig, VariantInfo, TypeScheme};
use middle::ty::{Disr, ParamTy, ParameterEnvironment};
......@@ -1947,6 +1947,43 @@ pub fn instantiate_type(&self,
}
}
/// Returns the type that this AST path refers to. If the path has no type
/// parameters and the corresponding type has type parameters, fresh type
/// and/or region variables are substituted.
///
/// This is used when checking the constructor in struct literals.
fn instantiate_struct_literal_ty(&self,
did: ast::DefId,
path: &ast::Path)
-> TypeAndSubsts<'tcx>
{
let tcx = self.tcx();
let ty::TypeScheme { generics, ty: decl_ty } = ty::lookup_item_type(tcx, did);
let wants_params =
generics.has_type_params(TypeSpace) || generics.has_region_params(TypeSpace);
let needs_defaults =
wants_params &&
path.segments.iter().all(|s| s.parameters.is_empty());
let substs = if needs_defaults {
let tps =
self.infcx().next_ty_vars(generics.types.len(TypeSpace));
let rps =
self.infcx().region_vars_for_defs(path.span,
generics.regions.get_slice(TypeSpace));
Substs::new_type(tps, rps)
} else {
astconv::ast_path_substs_for_ty(self, self, &generics, path)
};
let ty = self.instantiate_type_scheme(path.span, &substs, &decl_ty);
TypeAndSubsts { substs: substs, ty: ty }
}
pub fn write_nil(&self, node_id: ast::NodeId) {
self.write_ty(node_id, ty::mk_nil(self.tcx()));
}
......@@ -3490,17 +3527,18 @@ fn check_struct_or_variant_fields<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
expected_field_type =
ty::lookup_field_type(
tcx, class_id, field_id, substitutions);
expected_field_type =
fcx.normalize_associated_types_in(
field.span, &expected_field_type);
class_field_map.insert(
field.ident.node.name, (field_id, true));
fields_found += 1;
}
}
// Make sure to give a type to the field even if there's
// an error, so we can continue typechecking
check_expr_coercable_to_type(
fcx,
&*field.expr,
expected_field_type);
check_expr_coercable_to_type(fcx, &*field.expr, expected_field_type);
}
if error_happened {
......@@ -4149,10 +4187,7 @@ fn check_struct_fields_on_error(fcx: &FnCtxt,
// parameters correctly.
let actual_structure_type = fcx.expr_ty(&*expr);
if !ty::type_is_error(actual_structure_type) {
let type_and_substs = astconv::ast_path_to_ty_relaxed(fcx,
fcx,
struct_id,
path);
let type_and_substs = fcx.instantiate_struct_literal_ty(struct_id, path);
match fcx.mk_subty(false,
infer::Misc(path.span),
actual_structure_type,
......
// Copyright 2014 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.
// Test associated type references in a struct literal. Issue #20535.
pub trait Foo {
type Bar;
}
impl Foo for int {
type Bar = int;
}
struct Thing<F: Foo> {
a: F,
b: F::Bar,
}
fn main() {
let thing = Thing{a: 1i, b: 2i};
assert_eq!(thing.a + 1, thing.b);
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册