Skip to content

More associated types "fun" #21107

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 16, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2604,12 +2604,17 @@ impl FlagComputation {

&ty_projection(ref data) => {
self.add_flags(HAS_PROJECTION);
self.add_substs(data.trait_ref.substs);
self.add_projection_ty(data);
}

&ty_trait(box TyTrait { ref principal, ref bounds }) => {
let mut computation = FlagComputation::new();
computation.add_substs(principal.0.substs);
for projection_bound in bounds.projection_bounds.iter() {
let mut proj_computation = FlagComputation::new();
proj_computation.add_projection_predicate(&projection_bound.0);
computation.add_bound_computation(&proj_computation);
}
self.add_bound_computation(&computation);

self.add_bounds(bounds);
Expand Down Expand Up @@ -2673,6 +2678,15 @@ impl FlagComputation {
}
}

fn add_projection_predicate(&mut self, projection_predicate: &ProjectionPredicate) {
self.add_projection_ty(&projection_predicate.projection_ty);
self.add_ty(projection_predicate.ty);
}

fn add_projection_ty(&mut self, projection_ty: &ProjectionTy) {
self.add_substs(projection_ty.trait_ref.substs);
}

fn add_substs(&mut self, substs: &Substs) {
self.add_tys(substs.types.as_slice());
match substs.regions {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/util/ppaux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1430,7 +1430,7 @@ impl<'tcx> UserString<'tcx> for ty::ProjectionPredicate<'tcx> {
impl<'tcx> Repr<'tcx> for ty::ProjectionTy<'tcx> {
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
format!("<{} as {}>::{}",
self.trait_ref.self_ty().repr(tcx),
self.trait_ref.substs.self_ty().repr(tcx),
self.trait_ref.repr(tcx),
self.item_name.repr(tcx))
}
Expand Down
11 changes: 7 additions & 4 deletions src/librustc_trans/trans/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,12 +217,15 @@ pub fn type_needs_drop<'tcx>(cx: &ty::ctxt<'tcx>,
ty::type_contents(cx, ty).needs_drop(cx)
}

fn type_is_newtype_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
ty: Ty<'tcx>) -> bool {
fn type_is_newtype_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool {
match ty.sty {
ty::ty_struct(def_id, substs) => {
let fields = ty::struct_fields(ccx.tcx(), def_id, substs);
fields.len() == 1 && type_is_immediate(ccx, fields[0].mt.ty)
let fields = ty::lookup_struct_fields(ccx.tcx(), def_id);
fields.len() == 1 && {
let ty = ty::lookup_field_type(ccx.tcx(), def_id, fields[0].id, substs);
let ty = monomorphize::normalize_associated_type(ccx.tcx(), &ty);
type_is_immediate(ccx, ty)
}
}
_ => false
}
Expand Down
80 changes: 22 additions & 58 deletions src/librustc_trans/trans/debuginfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,28 +323,26 @@ impl<'tcx> TypeMap<'tcx> {
fn get_unique_type_id_of_type<'a>(&mut self, cx: &CrateContext<'a, 'tcx>,
type_: Ty<'tcx>) -> UniqueTypeId {

// basic type -> {:name of the type:}
// tuple -> {tuple_(:param-uid:)*}
// struct -> {struct_:svh: / :node-id:_<(:param-uid:),*> }
// enum -> {enum_:svh: / :node-id:_<(:param-uid:),*> }
// enum variant -> {variant_:variant-name:_:enum-uid:}
// reference (&) -> {& :pointee-uid:}
// mut reference (&mut) -> {&mut :pointee-uid:}
// ptr (*) -> {* :pointee-uid:}
// mut ptr (*mut) -> {*mut :pointee-uid:}
// unique ptr (~) -> {~ :pointee-uid:}
// @-ptr (@) -> {@ :pointee-uid:}
// sized vec ([T; x]) -> {[:size:] :element-uid:}
// unsized vec ([T]) -> {[] :element-uid:}
// trait (T) -> {trait_:svh: / :node-id:_<(:param-uid:),*> }
// closure -> {<unsafe_> <once_> :store-sigil:
// |(:param-uid:),* <,_...>| -> \
// :return-type-uid: : (:bounds:)*}
// function -> {<unsafe_> <abi_> fn( (:param-uid:)* <,_...> ) -> \
// :return-type-uid:}
// unique vec box (~[]) -> {HEAP_VEC_BOX<:pointee-uid:>}
// gc box -> {GC_BOX<:pointee-uid:>}
// projection (<T as U>::V) -> {<:ty-uid: as :trait-uid:> :: :name-uid: }
// basic type -> {:name of the type:}
// tuple -> {tuple_(:param-uid:)*}
// struct -> {struct_:svh: / :node-id:_<(:param-uid:),*> }
// enum -> {enum_:svh: / :node-id:_<(:param-uid:),*> }
// enum variant -> {variant_:variant-name:_:enum-uid:}
// reference (&) -> {& :pointee-uid:}
// mut reference (&mut) -> {&mut :pointee-uid:}
// ptr (*) -> {* :pointee-uid:}
// mut ptr (*mut) -> {*mut :pointee-uid:}
// unique ptr (~) -> {~ :pointee-uid:}
// @-ptr (@) -> {@ :pointee-uid:}
// sized vec ([T; x]) -> {[:size:] :element-uid:}
// unsized vec ([T]) -> {[] :element-uid:}
// trait (T) -> {trait_:svh: / :node-id:_<(:param-uid:),*> }
// closure -> {<unsafe_> <once_> :store-sigil: |(:param-uid:),* <,_...>| -> \
// :return-type-uid: : (:bounds:)*}
// function -> {<unsafe_> <abi_> fn( (:param-uid:)* <,_...> ) -> \
// :return-type-uid:}
// unique vec box (~[]) -> {HEAP_VEC_BOX<:pointee-uid:>}
// gc box -> {GC_BOX<:pointee-uid:>}

match self.type_to_unique_id.get(&type_).cloned() {
Some(unique_type_id) => return unique_type_id,
Expand Down Expand Up @@ -437,25 +435,6 @@ impl<'tcx> TypeMap<'tcx> {
principal.substs,
&mut unique_type_id);
},
ty::ty_projection(ref projection) => {
unique_type_id.push_str("<");

let self_ty = projection.trait_ref.self_ty();
let self_type_id = self.get_unique_type_id_of_type(cx, self_ty);
let self_type_id = self.get_unique_type_id_as_string(self_type_id);
unique_type_id.push_str(&self_type_id[]);

unique_type_id.push_str(" as ");

from_def_id_and_substs(self,
cx,
projection.trait_ref.def_id,
projection.trait_ref.substs,
&mut unique_type_id);

unique_type_id.push_str(">::");
unique_type_id.push_str(token::get_name(projection.item_name).get());
},
ty::ty_bare_fn(_, &ty::BareFnTy{ unsafety, abi, ref sig } ) => {
if unsafety == ast::Unsafety::Unsafe {
unique_type_id.push_str("unsafe ");
Expand Down Expand Up @@ -499,10 +478,7 @@ impl<'tcx> TypeMap<'tcx> {
closure_ty,
&mut unique_type_id);
},
ty::ty_err |
ty::ty_infer(_) |
ty::ty_open(_) |
ty::ty_param(_) => {
_ => {
cx.sess().bug(&format!("get_unique_type_id_of_type() - unexpected type: {}, {:?}",
&ppaux::ty_to_string(cx.tcx(), type_)[],
type_.sty)[])
Expand Down Expand Up @@ -3879,22 +3855,10 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
ty::ty_unboxed_closure(..) => {
output.push_str("closure");
}
ty::ty_projection(ref projection) => {
output.push_str("<");
let self_ty = projection.trait_ref.self_ty();
push_debuginfo_type_name(cx, self_ty, true, output);

output.push_str(" as ");

push_item_name(cx, projection.trait_ref.def_id, false, output);
push_type_params(cx, projection.trait_ref.substs, output);

output.push_str(">::");
output.push_str(token::get_name(projection.item_name).get());
}
ty::ty_err |
ty::ty_infer(_) |
ty::ty_open(_) |
ty::ty_projection(..) |
ty::ty_param(_) => {
cx.sess().bug(&format!("debuginfo: Trying to create type name for \
unexpected type: {}", ppaux::ty_to_string(cx.tcx(), t))[]);
Expand Down
74 changes: 45 additions & 29 deletions src/librustc_typeck/astconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -516,8 +516,15 @@ pub fn instantiate_poly_trait_ref<'tcx>(
{
let mut projections = Vec::new();

// the trait reference introduces a binding level here, so
// we need to shift the `rscope`. It'd be nice if we could
// do away with this rscope stuff and work this knowledge
// into resolve_lifetimes, as we do with non-omitted
// lifetimes. Oh well, not there yet.
let shifted_rscope = ShiftedRscope::new(rscope);

let trait_ref =
instantiate_trait_ref(this, rscope, &ast_trait_ref.trait_ref,
instantiate_trait_ref(this, &shifted_rscope, &ast_trait_ref.trait_ref,
self_ty, Some(&mut projections));

for projection in projections.into_iter() {
Expand Down Expand Up @@ -561,6 +568,29 @@ pub fn instantiate_trait_ref<'tcx>(
}
}

fn object_path_to_poly_trait_ref<'a,'tcx>(
this: &AstConv<'tcx>,
rscope: &RegionScope,
trait_def_id: ast::DefId,
path: &ast::Path,
mut projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
-> ty::PolyTraitRef<'tcx>
{
// we are introducing a binder here, so shift the
// anonymous regions depth to account for that
let shifted_rscope = ShiftedRscope::new(rscope);

let mut tmp = Vec::new();
let trait_ref = ty::Binder(ast_path_to_trait_ref(this,
&shifted_rscope,
trait_def_id,
None,
path,
Some(&mut tmp)));
projections.extend(tmp.into_iter().map(ty::Binder));
trait_ref
}

fn ast_path_to_trait_ref<'a,'tcx>(
this: &AstConv<'tcx>,
rscope: &RegionScope,
Expand All @@ -573,13 +603,6 @@ fn ast_path_to_trait_ref<'a,'tcx>(
debug!("ast_path_to_trait_ref {:?}", path);
let trait_def = this.get_trait_def(trait_def_id);

// the trait reference introduces a binding level here, so
// we need to shift the `rscope`. It'd be nice if we could
// do away with this rscope stuff and work this knowledge
// into resolve_lifetimes, as we do with non-omitted
// lifetimes. Oh well, not there yet.
let shifted_rscope = ShiftedRscope::new(rscope);

let (regions, types, assoc_bindings) = match path.segments.last().unwrap().parameters {
ast::AngleBracketedParameters(ref data) => {
// For now, require that parenthetical notation be used
Expand All @@ -595,7 +618,7 @@ fn ast_path_to_trait_ref<'a,'tcx>(
the crate attributes to enable");
}

convert_angle_bracketed_parameters(this, &shifted_rscope, data)
convert_angle_bracketed_parameters(this, rscope, data)
}
ast::ParenthesizedParameters(ref data) => {
// For now, require that parenthetical notation be used
Expand All @@ -616,7 +639,7 @@ fn ast_path_to_trait_ref<'a,'tcx>(
};

let substs = create_substs_for_ast_path(this,
&shifted_rscope,
rscope,
path.span,
&trait_def.generics,
self_ty,
Expand Down Expand Up @@ -851,15 +874,11 @@ fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>,
match this.tcx().def_map.borrow().get(&id) {
Some(&def::DefTrait(trait_def_id)) => {
let mut projection_bounds = Vec::new();
let trait_ref = ty::Binder(ast_path_to_trait_ref(this,
rscope,
trait_def_id,
None,
path,
Some(&mut projection_bounds)));
let projection_bounds = projection_bounds.into_iter()
.map(ty::Binder)
.collect();
let trait_ref = object_path_to_poly_trait_ref(this,
rscope,
trait_def_id,
path,
&mut projection_bounds);
Ok((trait_ref, projection_bounds))
}
_ => {
Expand Down Expand Up @@ -1095,16 +1114,13 @@ pub fn ast_ty_to_ty<'tcx>(
// N.B. this case overlaps somewhat with
// TyObjectSum, see that fn for details
let mut projection_bounds = Vec::new();
let trait_ref = ast_path_to_trait_ref(this,
rscope,
trait_def_id,
None,
path,
Some(&mut projection_bounds));
let trait_ref = ty::Binder(trait_ref);
let projection_bounds = projection_bounds.into_iter()
.map(ty::Binder)
.collect();

let trait_ref = object_path_to_poly_trait_ref(this,
rscope,
trait_def_id,
path,
&mut projection_bounds);

trait_ref_to_object_type(this, rscope, path.span,
trait_ref, projection_bounds, &[])
}
Expand Down
49 changes: 49 additions & 0 deletions src/test/compile-fail/issue-20831-debruijn.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright 2015 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.

// Regression test for #20831: debruijn index account was thrown off
// by the (anonymous) lifetime in `<Self as Publisher>::Output`
// below. Note that changing to a named lifetime made the problem go
// away.

use std::ops::{Shl, Shr};
use std::cell::RefCell;

pub trait Subscriber {
type Input;
}

pub trait Publisher<'a> {
type Output;
fn subscribe(&mut self, Box<Subscriber<Input=Self::Output> + 'a>);
}

pub trait Processor<'a> : Subscriber + Publisher<'a> { }

impl<'a, P> Processor<'a> for P where P : Subscriber + Publisher<'a> { }

struct MyStruct<'a> {
sub: Box<Subscriber<Input=u64> + 'a>
}

impl<'a> Publisher<'a> for MyStruct<'a> {
type Output = u64;
fn subscribe(&mut self, t : Box<Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
// Not obvious, but there is an implicit lifetime here -------^
//~^^ ERROR cannot infer
//
// The fact that `Publisher` is using an implicit lifetime is
// what was causing the debruijn accounting to be off, so
// leave it that way!
self.sub = t;
}
}

fn main() {}
32 changes: 32 additions & 0 deletions src/test/run-pass/associated-types-normalize-unifield-struct.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2015 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.

// Regression test for issue #21010: Normalize associated types in
// various special paths in the `type_is_immediate` function.

#![allow(unstable)]

pub trait OffsetState: Sized {}
pub trait Offset { type State: OffsetState; }

#[derive(Copy)] pub struct X;
impl Offset for X { type State = Y; }

#[derive(Copy)] pub struct Y;
impl OffsetState for Y {}

pub fn now() -> DateTime<X> { from_utc(Y) }

pub struct DateTime<Off: Offset> { pub offset: Off::State }
pub fn from_utc<Off: Offset>(offset: Off::State) -> DateTime<Off> { DateTime { offset: offset } }

pub fn main() {
let _x = now();
}
Loading