Skip to content

librustc: Have coherence check Copy kind bounds when determining whether parameter substitutions could possibly unify #4139

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

Closed
wants to merge 2 commits into from
Closed
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
3 changes: 2 additions & 1 deletion src/librustc/middle/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ fn classify(e: @expr,
ast::expr_vstore_slice => classify(e, def_map, tcx),
ast::expr_vstore_uniq |
ast::expr_vstore_box |
ast::expr_vstore_mut_box => non_const
ast::expr_vstore_mut_box |
ast::expr_vstore_mut_slice => non_const
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/trans/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,8 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
ast::expr_lit(@{node: ast::lit_str(s), _}) => {
return tvec::trans_lit_str(bcx, expr, s, dest);
}
ast::expr_vstore(contents, ast::expr_vstore_slice) => {
ast::expr_vstore(contents, ast::expr_vstore_slice) |
ast::expr_vstore(contents, ast::expr_vstore_mut_slice) => {
return tvec::trans_slice_vstore(bcx, expr, contents, dest);
}
ast::expr_vstore(contents, ast::expr_vstore_fixed(_)) => {
Expand Down
17 changes: 15 additions & 2 deletions src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ export kind_can_be_copied, kind_can_be_sent, kind_can_be_implicitly_copied;
export type_implicitly_moves;
export kind_is_safe_for_default_mode;
export kind_is_owned;
export meta_kind, kind_lteq, type_kind;
export meta_kind, kind_lteq, type_kind, type_kind_ext;
export operators;
export type_err, terr_vstore_kind;
export terr_mismatch, terr_onceness_mismatch;
Expand Down Expand Up @@ -2106,6 +2106,12 @@ fn mutable_type_kind(cx: ctxt, ty: mt) -> Kind {
}

fn type_kind(cx: ctxt, ty: t) -> Kind {
type_kind_ext(cx, ty, false)
}

// If `allow_ty_var` is true, then this is a conservative assumption; we
// assume that type variables *do* have all kinds.
fn type_kind_ext(cx: ctxt, ty: t, allow_ty_var: bool) -> Kind {
match cx.kind_cache.find(ty) {
Some(result) => return result,
None => {/* fall through */ }
Expand Down Expand Up @@ -2140,6 +2146,7 @@ fn type_kind(cx: ctxt, ty: t) -> Kind {
}

// Trait instances are (for now) like shared boxes, basically
// XXX: This is wrong for ~Trait and &Trait!
ty_trait(_, _, _) => kind_safe_for_default_mode() | kind_owned(),

// Static region pointers are copyable and sendable, but not owned
Expand Down Expand Up @@ -2254,8 +2261,13 @@ fn type_kind(cx: ctxt, ty: t) -> Kind {
ty_self => kind_noncopyable(),

ty_infer(_) => {
cx.sess.bug(~"Asked to compute kind of a type variable");
if allow_ty_var {
kind_top()
} else {
cx.sess.bug(~"Asked to compute kind of a type variable")
}
}

ty_type | ty_opaque_closure_ptr(_)
| ty_opaque_box | ty_unboxed_vec(_) | ty_err => {
cx.sess.bug(~"Asked to compute kind of fictitious type");
Expand Down Expand Up @@ -3099,6 +3111,7 @@ fn expr_kind(tcx: ctxt,
ast::expr_repeat(*) |
ast::expr_lit(@{node: lit_str(_), _}) |
ast::expr_vstore(_, ast::expr_vstore_slice) |
ast::expr_vstore(_, ast::expr_vstore_mut_slice) |
ast::expr_vstore(_, ast::expr_vstore_fixed(_)) |
ast::expr_vec(*) => {
RvalueDpsExpr
Expand Down
6 changes: 4 additions & 2 deletions src/librustc/middle/typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1804,7 +1804,9 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
let tt = ast_expr_vstore_to_vstore(fcx, ev, args.len(), vst);
let mutability;
match vst {
ast::expr_vstore_mut_box => mutability = ast::m_mutbl,
ast::expr_vstore_mut_box | ast::expr_vstore_mut_slice => {
mutability = ast::m_mutbl
}
_ => mutability = mutbl
}
let t: ty::t = fcx.infcx().next_ty_var();
Expand Down Expand Up @@ -2823,7 +2825,7 @@ fn ast_expr_vstore_to_vstore(fcx: @fn_ctxt, e: @ast::expr, n: uint,
}
ast::expr_vstore_uniq => ty::vstore_uniq,
ast::expr_vstore_box | ast::expr_vstore_mut_box => ty::vstore_box,
ast::expr_vstore_slice => {
ast::expr_vstore_slice | ast::expr_vstore_mut_slice => {
let r = fcx.infcx().next_region_var(e.span, e.id);
ty::vstore_slice(r)
}
Expand Down
106 changes: 88 additions & 18 deletions src/librustc/middle/typeck/coherence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,17 @@ use metadata::csearch::{get_impls_for_mod};
use metadata::cstore::{CStore, iter_crate_data};
use metadata::decoder::{dl_def, dl_field, dl_impl};
use middle::resolve::{Impl, MethodInfo};
use middle::ty::{DerivedMethodInfo, ProvidedMethodSource, get};
use middle::ty::{lookup_item_type, subst, t, ty_bot, ty_box, ty_class};
use middle::ty::{ty_bool, ty_enum, ty_int, ty_nil, ty_ptr, ty_rptr, ty_uint};
use middle::ty::{ty_float, ty_estr, ty_evec, ty_rec, ty_uniq};
use middle::ty::{ty_err, ty_fn, ty_trait, ty_tup, ty_infer};
use middle::ty::{DerivedMethodInfo, ProvidedMethodSource, bound_copy, get};
use middle::ty::{kind_can_be_copied, lookup_item_type, param_bounds, subst};
use middle::ty::{t, ty_bool, ty_bot, ty_box, ty_class, ty_enum, ty_err};
use middle::ty::{ty_estr, ty_evec, ty_float, ty_fn, ty_infer, ty_int, ty_nil};
use middle::ty::{ty_ptr, ty_rec, ty_rptr, ty_trait, ty_tup, ty_uint, ty_uniq};
use middle::ty::{ty_param, ty_self, ty_type, ty_opaque_box};
use middle::ty::{ty_opaque_closure_ptr, ty_unboxed_vec, type_is_ty_var};
use middle::ty::{ty_opaque_closure_ptr, ty_unboxed_vec, type_kind_ext};
use middle::ty::{type_is_ty_var};
use middle::typeck::infer::{infer_ctxt, can_mk_subty};
use middle::typeck::infer::{new_infer_ctxt, resolve_ivar, resolve_type};
use middle::typeck::infer::{new_infer_ctxt, resolve_ivar};
use middle::typeck::infer::{resolve_nested_tvar, resolve_type};
use syntax::ast::{crate, def_id, def_mod, def_ty};
use syntax::ast::{item, item_class, item_const, item_enum, item_fn};
use syntax::ast::{item_foreign_mod, item_impl, item_mac, item_mod};
Expand All @@ -48,6 +50,12 @@ use std::map::HashMap;
use uint::range;
use vec::{len, push};

struct UniversalQuantificationResult {
monotype: t,
type_variables: ~[ty::t],
bounds: @~[param_bounds]
}

fn get_base_type(inference_context: infer_ctxt, span: span, original_type: t)
-> Option<t> {

Expand Down Expand Up @@ -487,19 +495,21 @@ impl CoherenceChecker {
fn polytypes_unify(polytype_a: ty_param_bounds_and_ty,
polytype_b: ty_param_bounds_and_ty)
-> bool {

let monotype_a = self.universally_quantify_polytype(polytype_a);
let monotype_b = self.universally_quantify_polytype(polytype_b);
return can_mk_subty(self.inference_context,
monotype_a, monotype_b).is_ok()
|| can_mk_subty(self.inference_context,
monotype_b, monotype_a).is_ok();
let universally_quantified_a =
self.universally_quantify_polytype(polytype_a);
let universally_quantified_b =
self.universally_quantify_polytype(polytype_b);

return self.can_unify_universally_quantified(
&universally_quantified_a, &universally_quantified_b) ||
self.can_unify_universally_quantified(
&universally_quantified_b, &universally_quantified_a);
}

// Converts a polytype to a monotype by replacing all parameters with
// type variables.

fn universally_quantify_polytype(polytype: ty_param_bounds_and_ty) -> t {
// type variables. Returns the monotype and the type variables created.
fn universally_quantify_polytype(polytype: ty_param_bounds_and_ty)
-> UniversalQuantificationResult {
// NDM--this span is bogus.
let self_region =
polytype.region_param.map(
Expand All @@ -515,7 +525,67 @@ impl CoherenceChecker {
tps: type_parameters
};

return subst(self.crate_context.tcx, &substitutions, polytype.ty);
let monotype = subst(self.crate_context.tcx,
&substitutions,
polytype.ty);
UniversalQuantificationResult {
monotype: monotype,
type_variables: move type_parameters,
bounds: polytype.bounds
}
}

fn can_unify_universally_quantified(a: &a/UniversalQuantificationResult,
b: &a/UniversalQuantificationResult)
-> bool {
let mut might_unify = true;
let _ = do self.inference_context.probe {
let result = self.inference_context.sub(true, dummy_sp())
.tys(a.monotype, b.monotype);
if result.is_ok() {
// Check to ensure that each parameter binding respected its
// kind bounds.
for [ a, b ].each |result| {
for vec::each2(result.type_variables, *result.bounds)
|ty_var, bounds| {
match resolve_type(self.inference_context,
*ty_var,
resolve_nested_tvar) {
Ok(resolved_ty) => {
for bounds.each |bound| {
match *bound {
bound_copy => {
let kind = type_kind_ext(
self.inference_context.tcx,
resolved_ty,
true);
if !kind_can_be_copied(kind) {
might_unify = false;
break;
}
}

// XXX: We could be smarter here.
// Check to see whether owned, send,
// const, trait param bounds could
// possibly unify.
_ => {}
}
}
}
Err(*) => {
// Conservatively assume it might unify.
}
}
}
}
} else {
might_unify = false;
}

result
};
might_unify
}

fn get_self_type_for_implementation(implementation: @Impl)
Expand Down
3 changes: 2 additions & 1 deletion src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,8 @@ enum expr_vstore {
expr_vstore_uniq, // ~[1,2,3,4]
expr_vstore_box, // @[1,2,3,4]
expr_vstore_mut_box, // @mut [1,2,3,4]
expr_vstore_slice // &[1,2,3,4]
expr_vstore_slice, // &[1,2,3,4]
expr_vstore_mut_slice, // &mut [1,2,3,4]
}

pure fn is_blockish(p: ast::Proto) -> bool {
Expand Down
5 changes: 4 additions & 1 deletion src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ use ast::{_mod, add, arg, arm, attribute,
expr_method_call, expr_paren, expr_path, expr_rec, expr_repeat,
expr_ret, expr_swap, expr_struct, expr_tup, expr_unary,
expr_unary_move, expr_vec, expr_vstore, expr_vstore_mut_box,
expr_while, extern_fn, field, fn_decl,
expr_vstore_mut_slice, expr_while, extern_fn, field, fn_decl,
foreign_item, foreign_item_const, foreign_item_fn, foreign_mod,
ident, impure_fn, infer, inherited,
item, item_, item_class, item_const, item_enum, item_fn,
Expand Down Expand Up @@ -1456,6 +1456,9 @@ impl Parser {
if m == m_imm => {
expr_vstore(e, expr_vstore_slice)
}
expr_vec(*) if m == m_mutbl => {
expr_vstore(e, expr_vstore_mut_slice)
}
_ => expr_addr_of(m, e)
};
}
Expand Down
4 changes: 4 additions & 0 deletions src/libsyntax/print/pprust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1049,6 +1049,10 @@ fn print_expr_vstore(s: ps, t: ast::expr_vstore) {
word(s.s, ~"mut");
}
ast::expr_vstore_slice => word(s.s, ~"&"),
ast::expr_vstore_mut_slice => {
word(s.s, ~"&");
word(s.s, ~"mut");
}
}
}

Expand Down
13 changes: 13 additions & 0 deletions src/test/run-pass/coherence-copy-bound.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
trait X {}

impl<A:Copy> A : X {}

struct S {
x: int,
drop {}
}

impl S : X {}

fn main(){}

4 changes: 4 additions & 0 deletions src/test/run-pass/mut-vstore-expr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
fn main() {
let x: &mut [int] = &mut [ 1, 2, 3 ];
}