rollup merge of #20706: nikomatsakis/assoc-types-projections-in-structs-issue-20470
Conflicts: src/librustc_trans/trans/expr.rs
This commit is contained in:
commit
bcebec5084
@ -135,10 +135,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
|
||||
t
|
||||
}
|
||||
|
||||
ty::ty_open(..) => {
|
||||
self.tcx().sess.bug("Cannot freshen an open existential type");
|
||||
}
|
||||
|
||||
ty::ty_open(..) |
|
||||
ty::ty_bool |
|
||||
ty::ty_char |
|
||||
ty::ty_int(..) |
|
||||
|
@ -1457,11 +1457,26 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
Ok(AmbiguousBuiltin)
|
||||
}
|
||||
|
||||
ty::ty_open(ty) => {
|
||||
// these only crop up in trans, and represent an
|
||||
// "opened" unsized/existential type (one that has
|
||||
// been dereferenced)
|
||||
match bound {
|
||||
ty::BoundCopy |
|
||||
ty::BoundSync |
|
||||
ty::BoundSend => {
|
||||
Ok(If(vec!(ty)))
|
||||
}
|
||||
|
||||
ty::BoundSized => {
|
||||
Err(Unimplemented)
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::ty_err => {
|
||||
Ok(If(Vec::new()))
|
||||
}
|
||||
|
||||
ty::ty_open(_) |
|
||||
ty::ty_infer(ty::FreshTy(_)) |
|
||||
ty::ty_infer(ty::FreshIntTy(_)) => {
|
||||
self.tcx().sess.bug(
|
||||
|
@ -107,7 +107,7 @@ pub struct CrateAnalysis<'tcx> {
|
||||
pub glob_map: Option<GlobMap>,
|
||||
}
|
||||
|
||||
#[derive(Copy, PartialEq, Eq, Hash)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct field<'tcx> {
|
||||
pub name: ast::Name,
|
||||
pub mt: mt<'tcx>
|
||||
@ -7240,6 +7240,12 @@ impl<'tcx> HasProjectionTypes for FnSig<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasProjectionTypes for field<'tcx> {
|
||||
fn has_projection_types(&self) -> bool {
|
||||
self.mt.ty.has_projection_types()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasProjectionTypes for BareFnTy<'tcx> {
|
||||
fn has_projection_types(&self) -> bool {
|
||||
self.sig.has_projection_types()
|
||||
@ -7339,3 +7345,11 @@ impl<'tcx> Repr<'tcx> for UnboxedClosureUpvar<'tcx> {
|
||||
self.ty.repr(tcx))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for field<'tcx> {
|
||||
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
|
||||
format!("field({},{})",
|
||||
self.name.repr(tcx),
|
||||
self.mt.repr(tcx))
|
||||
}
|
||||
}
|
||||
|
@ -273,6 +273,15 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TraitRef<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for ty::field<'tcx> {
|
||||
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::field<'tcx> {
|
||||
ty::field {
|
||||
name: self.name,
|
||||
mt: self.mt.fold_with(folder),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for ty::Region {
|
||||
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Region {
|
||||
folder.fold_region(*self)
|
||||
|
@ -51,7 +51,11 @@ use std::rc::Rc;
|
||||
use llvm::{ValueRef, True, IntEQ, IntNE};
|
||||
use back::abi::FAT_PTR_ADDR;
|
||||
use middle::subst;
|
||||
use middle::subst::Subst;
|
||||
use middle::ty::{mod, Ty, UnboxedClosureTyper};
|
||||
use middle::ty::Disr;
|
||||
use syntax::ast;
|
||||
use syntax::attr;
|
||||
use syntax::attr::IntType;
|
||||
use trans::_match;
|
||||
use trans::build::*;
|
||||
use trans::cleanup;
|
||||
@ -59,13 +63,9 @@ use trans::cleanup::CleanupMethods;
|
||||
use trans::common::*;
|
||||
use trans::datum;
|
||||
use trans::machine;
|
||||
use trans::monomorphize;
|
||||
use trans::type_::Type;
|
||||
use trans::type_of;
|
||||
use middle::ty::{self, Ty, UnboxedClosureTyper};
|
||||
use middle::ty::Disr;
|
||||
use syntax::ast;
|
||||
use syntax::attr;
|
||||
use syntax::attr::IntType;
|
||||
use util::ppaux::ty_to_string;
|
||||
|
||||
type Hint = attr::ReprAttr;
|
||||
@ -159,7 +159,8 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
ty::ty_struct(def_id, substs) => {
|
||||
let fields = ty::lookup_struct_fields(cx.tcx(), def_id);
|
||||
let mut ftys = fields.iter().map(|field| {
|
||||
ty::lookup_field_type(cx.tcx(), def_id, field.id, substs)
|
||||
let fty = ty::lookup_field_type(cx.tcx(), def_id, field.id, substs);
|
||||
monomorphize::normalize_associated_type(cx.tcx(), &fty)
|
||||
}).collect::<Vec<_>>();
|
||||
let packed = ty::lookup_packed(cx.tcx(), def_id);
|
||||
let dtor = ty::ty_dtor(cx.tcx(), def_id).has_drop_flag();
|
||||
@ -432,7 +433,7 @@ fn get_cases<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
-> Vec<Case<'tcx>> {
|
||||
ty::enum_variants(tcx, def_id).iter().map(|vi| {
|
||||
let arg_tys = vi.args.iter().map(|&raw_ty| {
|
||||
raw_ty.subst(tcx, substs)
|
||||
monomorphize::apply_param_substs(tcx, substs, &raw_ty)
|
||||
}).collect();
|
||||
Case { discr: vi.disr_val, tys: arg_tys }
|
||||
}).collect()
|
||||
|
@ -50,7 +50,7 @@ use std::vec::Vec;
|
||||
use syntax::ast::Ident;
|
||||
use syntax::ast;
|
||||
use syntax::ast_map::{PathElem, PathName};
|
||||
use syntax::codemap::Span;
|
||||
use syntax::codemap::{DUMMY_SP, Span};
|
||||
use syntax::parse::token::InternedString;
|
||||
use syntax::parse::token;
|
||||
use util::common::memoized;
|
||||
@ -114,8 +114,9 @@ pub fn normalize_ty<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
}
|
||||
|
||||
// Is the type's representation size known at compile time?
|
||||
pub fn type_is_sized<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
ty::type_contents(cx, ty).is_sized(cx)
|
||||
pub fn type_is_sized<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
let param_env = ty::empty_parameter_environment(tcx);
|
||||
ty::type_is_sized(¶m_env, DUMMY_SP, ty)
|
||||
}
|
||||
|
||||
pub fn lltype_is_sized<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
|
@ -50,6 +50,7 @@ use trans::debuginfo;
|
||||
use trans::glue;
|
||||
use trans::machine;
|
||||
use trans::meth;
|
||||
use trans::monomorphize;
|
||||
use trans::inline;
|
||||
use trans::tvec;
|
||||
use trans::type_of;
|
||||
@ -1318,7 +1319,9 @@ pub fn with_field_tys<'tcx, R, F>(tcx: &ty::ctxt<'tcx>,
|
||||
{
|
||||
match ty.sty {
|
||||
ty::ty_struct(did, substs) => {
|
||||
op(0, &struct_fields(tcx, did, substs)[])
|
||||
let fields = struct_fields(tcx, did, substs);
|
||||
let fields = monomorphize::normalize_associated_type(tcx, &fields);
|
||||
op(0, &fields[])
|
||||
}
|
||||
|
||||
ty::ty_tup(ref v) => {
|
||||
@ -1340,10 +1343,9 @@ pub fn with_field_tys<'tcx, R, F>(tcx: &ty::ctxt<'tcx>,
|
||||
def::DefVariant(enum_id, variant_id, _) => {
|
||||
let variant_info = ty::enum_variant_with_id(
|
||||
tcx, enum_id, variant_id);
|
||||
op(variant_info.disr_val,
|
||||
&struct_fields(tcx,
|
||||
variant_id,
|
||||
substs)[])
|
||||
let fields = struct_fields(tcx, variant_id, substs);
|
||||
let fields = monomorphize::normalize_associated_type(tcx, &fields);
|
||||
op(variant_info.disr_val, &fields.index[])
|
||||
}
|
||||
_ => {
|
||||
tcx.sess.bug("resolve didn't map this expr to a \
|
||||
|
@ -300,8 +300,6 @@ pub fn apply_param_substs<'tcx,T>(tcx: &ty::ctxt<'tcx>,
|
||||
-> T
|
||||
where T : TypeFoldable<'tcx> + Repr<'tcx> + HasProjectionTypes + Clone
|
||||
{
|
||||
assert!(param_substs.regions.is_erased());
|
||||
|
||||
let substituted = value.subst(tcx, param_substs);
|
||||
normalize_associated_type(tcx, &substituted)
|
||||
}
|
||||
|
@ -52,7 +52,6 @@ use middle::const_eval;
|
||||
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 as mc;
|
||||
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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// 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_expr_with_unifier<'a, 'tcx, F>(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_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
// 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,
|
||||
|
@ -8,6 +8,13 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//~^^^^^^^^^^ ERROR overflow
|
||||
//
|
||||
// We also get a second error message at the top of file (dummy
|
||||
// span). This is not helpful, but also kind of annoying to prevent,
|
||||
// so for now just live with it, since we also get a second message
|
||||
// that is more helpful.
|
||||
|
||||
enum Nil {NilValue}
|
||||
struct Cons<T> {head:int, tail:T}
|
||||
trait Dot {fn dot(&self, other:Self) -> int;}
|
||||
|
62
src/test/run-pass/associated-types-ref-from-struct.rs
Normal file
62
src/test/run-pass/associated-types-ref-from-struct.rs
Normal file
@ -0,0 +1,62 @@
|
||||
// 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 structure fields.
|
||||
|
||||
trait Test {
|
||||
type V;
|
||||
|
||||
fn test(&self, value: &Self::V) -> bool;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct TesterPair<T:Test> {
|
||||
tester: T,
|
||||
value: T::V,
|
||||
}
|
||||
|
||||
impl<T:Test> TesterPair<T> {
|
||||
fn new(tester: T, value: T::V) -> TesterPair<T> {
|
||||
TesterPair { tester: tester, value: value }
|
||||
}
|
||||
|
||||
fn test(&self) -> bool {
|
||||
self.tester.test(&self.value)
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct EqU32(u32);
|
||||
impl Test for EqU32 {
|
||||
type V = u32;
|
||||
|
||||
fn test(&self, value: &u32) -> bool {
|
||||
self.0 == *value
|
||||
}
|
||||
}
|
||||
|
||||
struct EqI32(i32);
|
||||
impl Test for EqI32 {
|
||||
type V = i32;
|
||||
|
||||
fn test(&self, value: &i32) -> bool {
|
||||
self.0 == *value
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let tester = TesterPair::new(EqU32(22), 23);
|
||||
tester.test();
|
||||
|
||||
let tester = TesterPair::new(EqI32(22), 23);
|
||||
tester.test();
|
||||
}
|
29
src/test/run-pass/associated-types-ref-in-struct-literal.rs
Normal file
29
src/test/run-pass/associated-types-ref-in-struct-literal.rs
Normal file
@ -0,0 +1,29 @@
|
||||
// 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);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user