diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 5b3eb1e7266cd..f483f922ed7ac 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -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 } } diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index e2cb652a537fe..93458e31e6333 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -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(_)) => { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 58e01d4259003..88c39cc5116c4 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -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; @@ -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 */ } @@ -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 @@ -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"); @@ -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 diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index ecd29a6f6431d..db16d3d15a421 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -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(); @@ -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) } diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index c1517d11f73ad..b88f840ead587 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -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}; @@ -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 { @@ -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( @@ -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) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 1e7e427a38415..f719df3e6afa8 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -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 { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 86907706bbf77..42d1295dfb5d2 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -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, @@ -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) }; } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 14ef7c56b76db..73b47b82625dd 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -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"); + } } } diff --git a/src/test/run-pass/coherence-copy-bound.rs b/src/test/run-pass/coherence-copy-bound.rs new file mode 100644 index 0000000000000..fc6c159211978 --- /dev/null +++ b/src/test/run-pass/coherence-copy-bound.rs @@ -0,0 +1,13 @@ +trait X {} + +impl A : X {} + +struct S { + x: int, + drop {} +} + +impl S : X {} + +fn main(){} + diff --git a/src/test/run-pass/mut-vstore-expr.rs b/src/test/run-pass/mut-vstore-expr.rs new file mode 100644 index 0000000000000..3eb0209b4f9c8 --- /dev/null +++ b/src/test/run-pass/mut-vstore-expr.rs @@ -0,0 +1,4 @@ +fn main() { + let x: &mut [int] = &mut [ 1, 2, 3 ]; +} +