Skip to content
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

Move fn safety out of the subtyping relationship and into coercions #23452

Merged
merged 2 commits into from
Mar 18, 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
11 changes: 10 additions & 1 deletion src/librustc/middle/astencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -993,8 +993,14 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
})
}

ty::AdjustUnsafeFnPointer => {
this.emit_enum_variant("AdjustUnsafeFnPointer", 2, 0, |_| {
Ok(())
})
}

ty::AdjustDerefRef(ref auto_deref_ref) => {
this.emit_enum_variant("AdjustDerefRef", 2, 2, |this| {
this.emit_enum_variant("AdjustDerefRef", 3, 2, |this| {
this.emit_enum_variant_arg(0,
|this| Ok(this.emit_auto_deref_ref(ecx, auto_deref_ref)))
})
Expand Down Expand Up @@ -1619,6 +1625,9 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
ty::AdjustReifyFnPointer(def_id)
}
2 => {
ty::AdjustUnsafeFnPointer
}
3 => {
let auto_deref_ref: ty::AutoDerefRef =
this.read_enum_variant_arg(0,
|this| Ok(this.read_auto_deref_ref(dcx))).unwrap();
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -790,7 +790,8 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
None => { }
Some(adjustment) => {
match *adjustment {
ty::AdjustReifyFnPointer(..) => {
ty::AdjustReifyFnPointer(..) |
ty::AdjustUnsafeFnPointer(..) => {
// Creating a closure/fn-pointer consumes the
// input and stores it into the resulting
// rvalue.
Expand Down
20 changes: 0 additions & 20 deletions src/librustc/middle/infer/bivariate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ use middle::infer::{cres};
use middle::infer::type_variable::{BiTo};
use util::ppaux::{Repr};

use syntax::ast::{Unsafety};

pub struct Bivariate<'f, 'tcx: 'f> {
fields: CombineFields<'f, 'tcx>
}
Expand Down Expand Up @@ -74,24 +72,6 @@ impl<'f, 'tcx> Combine<'tcx> for Bivariate<'f, 'tcx> {
Ok(a)
}

fn mts(&self, a: &ty::mt<'tcx>, b: &ty::mt<'tcx>) -> cres<'tcx, ty::mt<'tcx>> {
debug!("mts({} <: {})",
a.repr(self.fields.infcx.tcx),
b.repr(self.fields.infcx.tcx));

if a.mutbl != b.mutbl { return Err(ty::terr_mutability); }
let t = try!(self.tys(a.ty, b.ty));
Ok(ty::mt { mutbl: a.mutbl, ty: t })
}

fn unsafeties(&self, a: Unsafety, b: Unsafety) -> cres<'tcx, Unsafety> {
if a != b {
Err(ty::terr_unsafety_mismatch(expected_found(self, a, b)))
} else {
Ok(a)
}
}

fn builtin_bounds(&self,
a: BuiltinBounds,
b: BuiltinBounds)
Expand Down
27 changes: 25 additions & 2 deletions src/librustc/middle/infer/combine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,24 @@ pub trait Combine<'tcx> : Sized {
fn lub<'a>(&'a self) -> Lub<'a, 'tcx> { Lub(self.fields().clone()) }
fn glb<'a>(&'a self) -> Glb<'a, 'tcx> { Glb(self.fields().clone()) }

fn mts(&self, a: &ty::mt<'tcx>, b: &ty::mt<'tcx>) -> cres<'tcx, ty::mt<'tcx>>;
fn mts(&self, a: &ty::mt<'tcx>, b: &ty::mt<'tcx>) -> cres<'tcx, ty::mt<'tcx>> {
debug!("{}.mts({}, {})",
self.tag(),
a.repr(self.tcx()),
b.repr(self.tcx()));

if a.mutbl != b.mutbl {
Err(ty::terr_mutability)
} else {
let mutbl = a.mutbl;
let variance = match mutbl {
ast::MutImmutable => ty::Covariant,
ast::MutMutable => ty::Invariant,
};
let ty = try!(self.tys_with_variance(variance, a.ty, b.ty));
Ok(ty::mt {ty: ty, mutbl: mutbl})
}
}

fn tys_with_variance(&self, variance: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
-> cres<'tcx, Ty<'tcx>>;
Expand Down Expand Up @@ -246,7 +263,13 @@ pub trait Combine<'tcx> : Sized {
self.tys_with_variance(ty::Contravariant, a, b).and_then(|t| Ok(t))
}

fn unsafeties(&self, a: Unsafety, b: Unsafety) -> cres<'tcx, Unsafety>;
fn unsafeties(&self, a: Unsafety, b: Unsafety) -> cres<'tcx, Unsafety> {
if a != b {
Err(ty::terr_unsafety_mismatch(expected_found(self, a, b)))
} else {
Ok(a)
}
}

fn abi(&self, a: abi::Abi, b: abi::Abi) -> cres<'tcx, abi::Abi> {
if a == b {
Expand Down
20 changes: 0 additions & 20 deletions src/librustc/middle/infer/equate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ use middle::infer::{Subtype};
use middle::infer::type_variable::{EqTo};
use util::ppaux::{Repr};

use syntax::ast::Unsafety;

pub struct Equate<'f, 'tcx: 'f> {
fields: CombineFields<'f, 'tcx>
}
Expand Down Expand Up @@ -54,24 +52,6 @@ impl<'f, 'tcx> Combine<'tcx> for Equate<'f, 'tcx> {
Ok(a)
}

fn mts(&self, a: &ty::mt<'tcx>, b: &ty::mt<'tcx>) -> cres<'tcx, ty::mt<'tcx>> {
debug!("mts({} <: {})",
a.repr(self.fields.infcx.tcx),
b.repr(self.fields.infcx.tcx));

if a.mutbl != b.mutbl { return Err(ty::terr_mutability); }
let t = try!(self.tys(a.ty, b.ty));
Ok(ty::mt { mutbl: a.mutbl, ty: t })
}

fn unsafeties(&self, a: Unsafety, b: Unsafety) -> cres<'tcx, Unsafety> {
if a != b {
Err(ty::terr_unsafety_mismatch(expected_found(self, a, b)))
} else {
Ok(a)
}
}

fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
debug!("{}.tys({}, {})", self.tag(),
a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx));
Expand Down
40 changes: 0 additions & 40 deletions src/librustc/middle/infer/glb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ use super::{cres};
use super::Subtype;

use middle::ty::{self, Ty};
use syntax::ast::{MutImmutable, MutMutable, Unsafety};
use util::ppaux::mt_to_string;
use util::ppaux::Repr;

/// "Greatest lower bound" (common subtype)
Expand Down Expand Up @@ -55,44 +53,6 @@ impl<'f, 'tcx> Combine<'tcx> for Glb<'f, 'tcx> {
}
}

fn mts(&self, a: &ty::mt<'tcx>, b: &ty::mt<'tcx>) -> cres<'tcx, ty::mt<'tcx>> {
let tcx = self.fields.infcx.tcx;

debug!("{}.mts({}, {})",
self.tag(),
mt_to_string(tcx, a),
mt_to_string(tcx, b));

match (a.mutbl, b.mutbl) {
// If one side or both is mut, then the GLB must use
// the precise type from the mut side.
(MutMutable, MutMutable) => {
let t = try!(self.equate().tys(a.ty, b.ty));
Ok(ty::mt {ty: t, mutbl: MutMutable})
}

// If one side or both is immutable, we can use the GLB of
// both sides but mutbl must be `MutImmutable`.
(MutImmutable, MutImmutable) => {
let t = try!(self.tys(a.ty, b.ty));
Ok(ty::mt {ty: t, mutbl: MutImmutable})
}

// There is no mutual subtype of these combinations.
(MutMutable, MutImmutable) |
(MutImmutable, MutMutable) => {
Err(ty::terr_mutability)
}
}
}

fn unsafeties(&self, a: Unsafety, b: Unsafety) -> cres<'tcx, Unsafety> {
match (a, b) {
(Unsafety::Normal, _) | (_, Unsafety::Normal) => Ok(Unsafety::Normal),
(Unsafety::Unsafe, Unsafety::Unsafe) => Ok(Unsafety::Unsafe)
}
}

fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> {
debug!("{}.regions({}, {})",
self.tag(),
Expand Down
35 changes: 0 additions & 35 deletions src/librustc/middle/infer/lub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ use super::{cres};
use super::{Subtype};

use middle::ty::{self, Ty};
use syntax::ast::{MutMutable, MutImmutable, Unsafety};
use util::ppaux::mt_to_string;
use util::ppaux::Repr;

/// "Least upper bound" (common supertype)
Expand Down Expand Up @@ -55,39 +53,6 @@ impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> {
}
}

fn mts(&self, a: &ty::mt<'tcx>, b: &ty::mt<'tcx>) -> cres<'tcx, ty::mt<'tcx>> {
let tcx = self.tcx();

debug!("{}.mts({}, {})",
self.tag(),
mt_to_string(tcx, a),
mt_to_string(tcx, b));

if a.mutbl != b.mutbl {
return Err(ty::terr_mutability)
}

let m = a.mutbl;
match m {
MutImmutable => {
let t = try!(self.tys(a.ty, b.ty));
Ok(ty::mt {ty: t, mutbl: m})
}

MutMutable => {
let t = try!(self.equate().tys(a.ty, b.ty));
Ok(ty::mt {ty: t, mutbl: m})
}
}
}

fn unsafeties(&self, a: Unsafety, b: Unsafety) -> cres<'tcx, Unsafety> {
match (a, b) {
(Unsafety::Unsafe, _) | (_, Unsafety::Unsafe) => Ok(Unsafety::Unsafe),
(Unsafety::Normal, Unsafety::Normal) => Ok(Unsafety::Normal),
}
}

fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> {
debug!("{}.regions({}, {})",
self.tag(),
Expand Down
35 changes: 1 addition & 34 deletions src/librustc/middle/infer/sub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
// except according to those terms.

use super::combine::*;
use super::{cres, CresCompare};
use super::{cres};
use super::higher_ranked::HigherRankedRelations;
use super::{Subtype};
use super::type_variable::{SubtypeOf, SupertypeOf};
Expand All @@ -18,9 +18,6 @@ use middle::ty::{self, Ty};
use middle::ty::TyVar;
use util::ppaux::{Repr};

use syntax::ast::{MutImmutable, MutMutable, Unsafety};


/// "Greatest lower bound" (common subtype)
pub struct Sub<'f, 'tcx: 'f> {
fields: CombineFields<'f, 'tcx>
Expand Down Expand Up @@ -66,36 +63,6 @@ impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> {
Ok(a)
}

fn mts(&self, a: &ty::mt<'tcx>, b: &ty::mt<'tcx>) -> cres<'tcx, ty::mt<'tcx>> {
debug!("mts({} <: {})",
a.repr(self.tcx()),
b.repr(self.tcx()));

if a.mutbl != b.mutbl {
return Err(ty::terr_mutability);
}

match b.mutbl {
MutMutable => {
// If supertype is mut, subtype must match exactly
// (i.e., invariant if mut):
try!(self.equate().tys(a.ty, b.ty));
}
MutImmutable => {
// Otherwise we can be covariant:
try!(self.tys(a.ty, b.ty));
}
}

Ok(*a) // return is meaningless in sub, just return *a
}

fn unsafeties(&self, a: Unsafety, b: Unsafety) -> cres<'tcx, Unsafety> {
self.lub().unsafeties(a, b).compare(b, || {
ty::terr_unsafety_mismatch(expected_found(self, a, b))
})
}

fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
debug!("{}.tys({}, {})", self.tag(),
a.repr(self.tcx()), b.repr(self.tcx()));
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,8 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {

Some(adjustment) => {
match *adjustment {
ty::AdjustReifyFnPointer(..) => {
ty::AdjustReifyFnPointer(..) |
ty::AdjustUnsafeFnPointer(..) => {
debug!("cat_expr(AdjustReifyFnPointer): {}",
expr.repr(self.tcx()));
// Convert a bare fn to a closure by adding NULL env.
Expand Down
28 changes: 28 additions & 0 deletions src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ pub enum Variance {
#[derive(Clone, Debug)]
pub enum AutoAdjustment<'tcx> {
AdjustReifyFnPointer(ast::DefId), // go from a fn-item type to a fn-pointer type
AdjustUnsafeFnPointer, // go from a safe fn pointer to an unsafe fn pointer
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoa, you can match against this with ty::AdjustUnsafeFnPointer(..), that's an interesting... feature.

AdjustDerefRef(AutoDerefRef<'tcx>)
}

Expand Down Expand Up @@ -2637,6 +2638,17 @@ impl<'tcx> ctxt<'tcx> {
substs
}

/// Create an unsafe fn ty based on a safe fn ty.
pub fn safe_to_unsafe_fn_ty(&self, bare_fn: &BareFnTy<'tcx>) -> Ty<'tcx> {
assert_eq!(bare_fn.unsafety, ast::Unsafety::Normal);
let unsafe_fn_ty_a = self.mk_bare_fn(ty::BareFnTy {
unsafety: ast::Unsafety::Unsafe,
abi: bare_fn.abi,
sig: bare_fn.sig.clone()
});
ty::mk_bare_fn(self, None, unsafe_fn_ty_a)
}

pub fn mk_bare_fn(&self, bare_fn: BareFnTy<'tcx>) -> &'tcx BareFnTy<'tcx> {
if let Some(bare_fn) = self.bare_fn_interner.borrow().get(&bare_fn) {
return *bare_fn;
Expand Down Expand Up @@ -4526,6 +4538,18 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>,
}
}

AdjustUnsafeFnPointer => {
match unadjusted_ty.sty {
ty::ty_bare_fn(None, b) => cx.safe_to_unsafe_fn_ty(b),
ref b => {
cx.sess.bug(
&format!("AdjustReifyFnPointer adjustment on non-fn-item: \
{:?}",
b));
}
}
}

AdjustDerefRef(ref adj) => {
let mut adjusted_ty = unadjusted_ty;

Expand Down Expand Up @@ -6695,6 +6719,7 @@ impl<'tcx> AutoAdjustment<'tcx> {
pub fn is_identity(&self) -> bool {
match *self {
AdjustReifyFnPointer(..) => false,
AdjustUnsafeFnPointer(..) => false,
AdjustDerefRef(ref r) => r.is_identity(),
}
}
Expand Down Expand Up @@ -6844,6 +6869,9 @@ impl<'tcx> Repr<'tcx> for AutoAdjustment<'tcx> {
AdjustReifyFnPointer(def_id) => {
format!("AdjustReifyFnPointer({})", def_id.repr(tcx))
}
AdjustUnsafeFnPointer => {
format!("AdjustUnsafeFnPointer")
}
AdjustDerefRef(ref data) => {
data.repr(tcx)
}
Expand Down
3 changes: 3 additions & 0 deletions src/librustc_trans/trans/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,9 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
// FIXME(#19925) once fn item types are
// zero-sized, we'll need to do something here
}
Some(ty::AdjustUnsafeFnPointer) => {
// purely a type-level thing
}
Some(ty::AdjustDerefRef(adj)) => {
let mut ty = ety;
// Save the last autoderef in case we can avoid it.
Expand Down
Loading