coercion.rs 17.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
// Copyright 2012 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.

S
Steve Klabnik 已提交
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
//! # Type Coercion
//!
//! Under certain circumstances we will coerce from one type to another,
//! for example by auto-borrowing.  This occurs in situations where the
//! compiler has a firm 'expected type' that was supplied from the user,
//! and where the actual type is similar to that expected type in purpose
//! but not in representation (so actual subtyping is inappropriate).
//!
//! ## Reborrowing
//!
//! Note that if we are expecting a reference, we will *reborrow*
//! even if the argument provided was already a reference.  This is
//! useful for freezing mut/const things (that is, when the expected is &T
//! but you have &const T or &mut T) and also for avoiding the linearity
//! of mut things (when the expected is &mut T and you have &mut T).  See
//! the various `src/test/run-pass/coerce-reborrow-*.rs` tests for
//! examples of where this is useful.
//!
//! ## Subtle note
//!
//! When deciding what type coercions to consider, we do not attempt to
//! resolve any type variables we may encounter.  This is because `b`
//! represents the expected type "as the user wrote it", meaning that if
//! the user defined a generic function like
//!
//!    fn foo<A>(a: A, b: A) { ... }
//!
//! and then we wrote `foo(&1, @2)`, we will not auto-borrow
//! either argument.  In older code we went to some lengths to
//! resolve the `b` variable, which could mean that we'd
//! auto-borrow later arguments but not earlier ones, which
//! seems very confusing.
//!
//! ## Subtler note
//!
//! However, right now, if the user manually specifies the
//! values for the type variables, as so:
//!
//!    foo::<&int>(@1, @2)
//!
//! then we *will* auto-borrow, because we can't distinguish this from a
//! function that declared `&int`.  This is inconsistent but it's easiest
//! at the moment. The right thing to do, I think, is to consider the
//! *unsubstituted* type when deciding whether to auto-borrow, but the
//! *substituted* type when considering the bounds and so forth. But most
//! of our methods don't give access to the unsubstituted type, and
//! rightly so because they'd be error-prone.  So maybe the thing to do is
//! to actually determine the kind of coercions that should occur
//! separately and pass them in.  Or maybe it's ok as is.  Anyway, it's
//! sort of a minor point so I've opted to leave it for later---after all
//! we may want to adjust precisely when coercions occur.
62

63
use check::{autoderef, FnCtxt, UnresolvedTypeAction};
64

M
Ms2ger 已提交
65
use middle::infer::{self, Coercion, TypeOrigin};
N
Nick Cameron 已提交
66 67
use middle::traits::{self, ObligationCause};
use middle::traits::{predicate_for_trait_def, report_selection_error};
68 69
use middle::ty::adjustment::{AutoAdjustment, AutoDerefRef, AdjustDerefRef};
use middle::ty::adjustment::{AutoPtr, AutoUnsafe, AdjustReifyFnPointer};
70
use middle::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer};
71
use middle::ty::{self, LvaluePreference, TypeAndMut, Ty, TyCtxt};
N
Niko Matsakis 已提交
72
use middle::ty::fold::TypeFoldable;
73
use middle::ty::error::TypeError;
74
use middle::ty::relate::RelateResult;
75
use util::common::indent;
76

N
Nick Cameron 已提交
77 78
use std::cell::RefCell;
use std::collections::VecDeque;
79
use rustc_front::hir;
80

81 82
struct Coerce<'a, 'tcx: 'a> {
    fcx: &'a FnCtxt<'a, 'tcx>,
83
    origin: infer::TypeOrigin,
N
Nick Cameron 已提交
84
    unsizing_obligations: RefCell<Vec<traits::PredicateObligation<'tcx>>>,
85 86
}

87
type CoerceResult<'tcx> = RelateResult<'tcx, Option<AutoAdjustment<'tcx>>>;
88

89
impl<'f, 'tcx> Coerce<'f, 'tcx> {
90
    fn tcx(&self) -> &TyCtxt<'tcx> {
91
        self.fcx.tcx()
92 93
    }

94
    fn subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
95
        try!(self.fcx.infcx().sub_types(false, self.origin.clone(), a, b));
96
        Ok(None) // No coercion required.
97 98
    }

99
    fn coerce(&self,
100
              expr_a: &hir::Expr,
101 102 103
              a: Ty<'tcx>,
              b: Ty<'tcx>)
              -> CoerceResult<'tcx> {
104 105 106
        debug!("Coerce.tys({:?} => {:?})",
               a,
               b);
107

108 109 110 111 112 113 114
        let a = self.fcx.infcx().shallow_resolve(a);

        // Just ignore error types.
        if a.references_error() || b.references_error() {
            return Ok(None);
        }

N
Nick Cameron 已提交
115
        // Consider coercing the subtype to a DST
116
        let unsize = self.coerce_unsized(a, b);
N
Nick Cameron 已提交
117 118 119 120
        if unsize.is_ok() {
            return unsize;
        }

121 122 123 124
        // Examine the supertype and consider auto-borrowing.
        //
        // Note: does not attempt to resolve type variables we encounter.
        // See above for details.
125
        match b.sty {
126
            ty::TyRawPtr(mt_b) => {
127
                return self.coerce_unsafe_ptr(a, b, mt_b.mutbl);
128 129
            }

130
            ty::TyRef(_, mt_b) => {
131
                return self.coerce_borrowed_pointer(expr_a, a, b, mt_b.mutbl);
132 133
            }

134 135
            _ => {}
        }
136

137
        match a.sty {
138
            ty::TyFnDef(_, _, a_f) => {
139 140 141 142
                // Function items are coercible to any closure
                // type; function pointers are not (that would
                // require double indirection).
                self.coerce_from_fn_item(a, a_f, b)
143
            }
144
            ty::TyFnPtr(a_f) => {
145 146 147 148 149 150 151 152 153
                // We permit coercion of fn pointers to drop the
                // unsafe qualifier.
                self.coerce_from_fn_pointer(a, a_f, b)
            }
            _ => {
                // Otherwise, just use subtyping rules.
                self.subtype(a, b)
            }
        }
154 155
    }

156 157 158
    /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`.
    /// To match `A` with `B`, autoderef will be performed,
    /// calling `deref`/`deref_mut` where necessary.
159
    fn coerce_borrowed_pointer(&self,
160
                               expr_a: &hir::Expr,
161 162
                               a: Ty<'tcx>,
                               b: Ty<'tcx>,
163
                               mutbl_b: hir::Mutability)
164
                               -> CoerceResult<'tcx> {
165 166 167
        debug!("coerce_borrowed_pointer(a={:?}, b={:?})",
               a,
               b);
168

169 170 171 172 173 174
        // If we have a parameter of type `&M T_a` and the value
        // provided is `expr`, we will be adding an implicit borrow,
        // meaning that we convert `f(expr)` to `f(&M *expr)`.  Therefore,
        // to type check, we will construct the type that `&M*expr` would
        // yield.

175
        match a.sty {
176
            ty::TyRef(_, mt_a) => {
177
                try!(coerce_mutbls(mt_a.mutbl, mutbl_b));
S
Seo Sanghyeon 已提交
178
            }
179
            _ => return self.subtype(a, b)
180
        }
181

182
        let coercion = Coercion(self.origin.span());
183 184
        let r_borrow = self.fcx.infcx().next_region_var(coercion);
        let r_borrow = self.tcx().mk_region(r_borrow);
185
        let autoref = Some(AutoPtr(r_borrow, mutbl_b));
186

187
        let lvalue_pref = LvaluePreference::from_mutbl(mutbl_b);
188 189 190 191 192 193 194 195 196 197 198 199 200
        let mut first_error = None;
        let (_, autoderefs, success) = autoderef(self.fcx,
                                                 expr_a.span,
                                                 a,
                                                 Some(expr_a),
                                                 UnresolvedTypeAction::Ignore,
                                                 lvalue_pref,
                                                 |inner_ty, autoderef| {
            if autoderef == 0 {
                // Don't let this pass, otherwise it would cause
                // &T to autoref to &&T.
                return None;
            }
201
            let ty = self.tcx().mk_ref(r_borrow,
202
                                        TypeAndMut {ty: inner_ty, mutbl: mutbl_b});
203
            if let Err(err) = self.subtype(ty, b) {
204 205 206 207 208 209 210 211 212 213 214 215 216
                if first_error.is_none() {
                    first_error = Some(err);
                }
                None
            } else {
                Some(())
            }
        });

        match success {
            Some(_) => {
                Ok(Some(AdjustDerefRef(AutoDerefRef {
                    autoderefs: autoderefs,
217 218
                    autoref: autoref,
                    unsize: None
219 220 221 222 223 224 225 226
                })))
            }
            None => {
                // Return original error as if overloaded deref was never
                // attempted, to avoid irrelevant/confusing error messages.
                Err(first_error.expect("coerce_borrowed_pointer failed with no error?"))
            }
        }
227 228 229
    }


230 231
    // &[T; n] or &mut [T; n] -> &[T]
    // or &mut [T; n] -> &mut [T]
N
Nick Cameron 已提交
232 233
    // or &Concrete -> &Trait, etc.
    fn coerce_unsized(&self,
N
Nick Cameron 已提交
234 235
                      source: Ty<'tcx>,
                      target: Ty<'tcx>)
236
                      -> CoerceResult<'tcx> {
237 238 239
        debug!("coerce_unsized(source={:?}, target={:?})",
               source,
               target);
N
Nick Cameron 已提交
240 241 242 243 244 245 246

        let traits = (self.tcx().lang_items.unsize_trait(),
                      self.tcx().lang_items.coerce_unsized_trait());
        let (unsize_did, coerce_unsized_did) = if let (Some(u), Some(cu)) = traits {
            (u, cu)
        } else {
            debug!("Missing Unsize or CoerceUnsized traits");
247
            return Err(TypeError::Mismatch);
N
Nick Cameron 已提交
248
        };
249

N
Nick Cameron 已提交
250 251 252
        // Note, we want to avoid unnecessary unsizing. We don't want to coerce to
        // a DST unless we have to. This currently comes out in the wash since
        // we can't unify [T] with U. But to properly support DST, we need to allow
N
Nick Cameron 已提交
253
        // that, at which point we will need extra checks on the target here.
N
Nick Cameron 已提交
254

N
Nick Cameron 已提交
255 256
        // Handle reborrows before selecting `Source: CoerceUnsized<Target>`.
        let (source, reborrow) = match (&source.sty, &target.sty) {
257
            (&ty::TyRef(_, mt_a), &ty::TyRef(_, mt_b)) => {
N
Nick Cameron 已提交
258 259 260 261 262
                try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl));

                let coercion = Coercion(self.origin.span());
                let r_borrow = self.fcx.infcx().next_region_var(coercion);
                let region = self.tcx().mk_region(r_borrow);
263
                (mt_a.ty, Some(AutoPtr(region, mt_b.mutbl)))
264
            }
265
            (&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) => {
N
Nick Cameron 已提交
266
                try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl));
267
                (mt_a.ty, Some(AutoUnsafe(mt_b.mutbl)))
268
            }
N
Nick Cameron 已提交
269 270
            _ => (source, None)
        };
271
        let source = source.adjust_for_autoref(self.tcx(), reborrow);
N
Nick Cameron 已提交
272

J
Jared Roesch 已提交
273
        let mut selcx = traits::SelectionContext::new(self.fcx.infcx());
N
Nick Cameron 已提交
274 275 276 277 278 279 280

        // Use a FIFO queue for this custom fulfillment procedure.
        let mut queue = VecDeque::new();
        let mut leftover_predicates = vec![];

        // Create an obligation for `Source: CoerceUnsized<Target>`.
        let cause = ObligationCause::misc(self.origin.span(), self.fcx.body_id);
N
Nick Cameron 已提交
281 282 283 284 285 286
        queue.push_back(predicate_for_trait_def(self.tcx(),
                                                cause,
                                                coerce_unsized_did,
                                                0,
                                                source,
                                                vec![target]));
N
Nick Cameron 已提交
287 288 289 290 291 292

        // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
        // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
        // inference might unify those two inner type variables later.
        let traits = [coerce_unsized_did, unsize_did];
        while let Some(obligation) = queue.pop_front() {
293
            debug!("coerce_unsized resolve step: {:?}", obligation);
N
Nick Cameron 已提交
294 295 296 297 298 299 300 301 302 303 304 305
            let trait_ref =  match obligation.predicate {
                ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => {
                    tr.clone()
                }
                _ => {
                    leftover_predicates.push(obligation);
                    continue;
                }
            };
            match selcx.select(&obligation.with(trait_ref)) {
                // Uncertain or unimplemented.
                Ok(None) | Err(traits::Unimplemented) => {
N
Nick Cameron 已提交
306
                    debug!("coerce_unsized: early return - can't prove obligation");
307
                    return Err(TypeError::Mismatch);
N
Nick Cameron 已提交
308
                }
N
Nick Cameron 已提交
309 310 311 312 313 314 315 316 317 318

                // Object safety violations or miscellaneous.
                Err(err) => {
                    report_selection_error(self.fcx.infcx(), &obligation, &err);
                    // Treat this like an obligation and follow through
                    // with the unsizing - the lack of a coercion should
                    // be silent, as it causes a type mismatch later.
                }

                Ok(Some(vtable)) => {
319 320 321
                    for obligation in vtable.nested_obligations() {
                        queue.push_back(obligation);
                    }
N
Nick Cameron 已提交
322
                }
N
Nick Cameron 已提交
323
            }
N
Nick Cameron 已提交
324 325 326 327 328
        }

        let mut obligations = self.unsizing_obligations.borrow_mut();
        assert!(obligations.is_empty());
        *obligations = leftover_predicates;
329 330 331 332 333 334

        let adjustment = AutoDerefRef {
            autoderefs: if reborrow.is_some() { 1 } else { 0 },
            autoref: reborrow,
            unsize: Some(target)
        };
335
        debug!("Success, coerced with {:?}", adjustment);
336
        Ok(Some(AdjustDerefRef(adjustment)))
N
Nick Cameron 已提交
337
    }
338

339 340 341 342 343 344 345 346 347 348 349
    fn coerce_from_fn_pointer(&self,
                           a: Ty<'tcx>,
                           fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
                           b: Ty<'tcx>)
                           -> CoerceResult<'tcx>
    {
        /*!
         * Attempts to coerce from the type of a Rust function item
         * into a closure or a `proc`.
         */

350 351
        let b = self.fcx.infcx().shallow_resolve(b);
        debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b);
352

353 354 355 356 357 358
        if let ty::TyFnPtr(fn_ty_b) = b.sty {
            match (fn_ty_a.unsafety, fn_ty_b.unsafety) {
                (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => {
                    let unsafe_a = self.tcx().safe_to_unsafe_fn_ty(fn_ty_a);
                    try!(self.subtype(unsafe_a, b));
                    return Ok(Some(AdjustUnsafeFnPointer));
359
                }
360
                _ => {}
361
            }
362 363
        }
        self.subtype(a, b)
364 365
    }

366 367
    fn coerce_from_fn_item(&self,
                           a: Ty<'tcx>,
H
Huon Wilson 已提交
368
                           fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
369
                           b: Ty<'tcx>)
370
                           -> CoerceResult<'tcx> {
371 372 373 374
        /*!
         * Attempts to coerce from the type of a Rust function item
         * into a closure or a `proc`.
         */
375

376 377
        let b = self.fcx.infcx().shallow_resolve(b);
        debug!("coerce_from_fn_item(a={:?}, b={:?})", a, b);
378

379 380 381 382 383
        match b.sty {
            ty::TyFnPtr(_) => {
                let a_fn_pointer = self.tcx().mk_ty(ty::TyFnPtr(fn_ty_a));
                try!(self.subtype(a_fn_pointer, b));
                Ok(Some(AdjustReifyFnPointer))
384
            }
385 386
            _ => self.subtype(a, b)
        }
387 388
    }

389 390 391
    fn coerce_unsafe_ptr(&self,
                         a: Ty<'tcx>,
                         b: Ty<'tcx>,
392
                         mutbl_b: hir::Mutability)
393
                         -> CoerceResult<'tcx> {
394 395 396
        debug!("coerce_unsafe_ptr(a={:?}, b={:?})",
               a,
               b);
397

398 399 400
        let (is_ref, mt_a) = match a.sty {
            ty::TyRef(_, mt) => (true, mt),
            ty::TyRawPtr(mt) => (false, mt),
401 402 403 404 405
            _ => {
                return self.subtype(a, b);
            }
        };

406
        // Check that the types which they point at are compatible.
407
        let a_unsafe = self.tcx().mk_ptr(ty::TypeAndMut{ mutbl: mutbl_b, ty: mt_a.ty });
408
        try!(self.subtype(a_unsafe, b));
409
        try!(coerce_mutbls(mt_a.mutbl, mutbl_b));
N
Niko Matsakis 已提交
410

411
        // Although references and unsafe ptrs have the same
N
Niko Matsakis 已提交
412
        // representation, we still register an AutoDerefRef so that
413
        // regionck knows that the region for `a` must be valid here.
414 415 416
        if is_ref {
            Ok(Some(AdjustDerefRef(AutoDerefRef {
                autoderefs: 1,
417
                autoref: Some(AutoUnsafe(mutbl_b)),
418 419
                unsize: None
            })))
420 421
        } else if mt_a.mutbl != mutbl_b {
            Ok(Some(AdjustMutToConstPointer))
422 423 424
        } else {
            Ok(None)
        }
425 426
    }
}
427

428 429 430 431 432 433
pub fn try<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                     expr: &hir::Expr,
                     a: Ty<'tcx>,
                     b: Ty<'tcx>)
                     -> RelateResult<'tcx, ()> {
    debug!("coercion::try({:?} -> {:?})", a, b);
N
Nick Cameron 已提交
434 435
    let mut unsizing_obligations = vec![];
    let adjustment = try!(indent(|| {
N
Rebased  
Nick Cameron 已提交
436
        fcx.infcx().commit_if_ok(|_| {
437
            let coerce = Coerce {
438
                fcx: fcx,
M
Ms2ger 已提交
439
                origin: TypeOrigin::ExprAssignable(expr.span),
N
Nick Cameron 已提交
440
                unsizing_obligations: RefCell::new(vec![])
441
            };
N
Nick Cameron 已提交
442 443 444
            let adjustment = try!(coerce.coerce(expr, a, b));
            unsizing_obligations = coerce.unsizing_obligations.into_inner();
            Ok(adjustment)
445
        })
446
    }));
447 448

    if let Some(AdjustDerefRef(auto)) = adjustment {
N
Nick Cameron 已提交
449 450 451
        if auto.unsize.is_some() {
            for obligation in unsizing_obligations {
                fcx.register_predicate(obligation);
452 453 454 455
            }
        }
    }

456
    if let Some(adjustment) = adjustment {
457
        debug!("Success, coerced with {:?}", adjustment);
458
        fcx.write_adjustment(expr.id, adjustment);
459 460
    }
    Ok(())
461 462
}

463 464
fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability,
                       to_mutbl: hir::Mutability)
465
                       -> CoerceResult<'tcx> {
466
    match (from_mutbl, to_mutbl) {
467 468 469 470
        (hir::MutMutable, hir::MutMutable) |
        (hir::MutImmutable, hir::MutImmutable) |
        (hir::MutMutable, hir::MutImmutable) => Ok(None),
        (hir::MutImmutable, hir::MutMutable) => Err(TypeError::Mutability)
471 472
    }
}