rollup merge of #20706: nikomatsakis/assoc-types-projections-in-structs-issue-20470

Conflicts:
	src/librustc_trans/trans/expr.rs
This commit is contained in:
Alex Crichton 2015-01-07 17:35:00 -08:00
commit bcebec5084
13 changed files with 204 additions and 79 deletions

View File

@ -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(..) |

View File

@ -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(

View File

@ -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))
}
}

View File

@ -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)

View File

@ -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()

View File

@ -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(&param_env, DUMMY_SP, ty)
}
pub fn lltype_is_sized<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {

View File

@ -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 \

View File

@ -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)
}

View File

@ -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>(

View File

@ -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,

View File

@ -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;}

View 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();
}

View 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);
}