<commit_before>// Copyright 2014 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

pub use compile_error::*;
pub use syntax::parse::token::InternedString;
pub use syntax::ast::*;

use syntax::codemap::DUMMY_SP;
use std::rc::Rc;

#[deriving(Clone)]
pub struct AttributeValue<T>
{
  pub value: Option<T>,
  pub span: Span,
  duplicate: DuplicateAttribute
}

impl<T: Clone> AttributeValue<T>
{
  pub fn new(duplicate: DuplicateAttribute) -> AttributeValue<T>
  {
    AttributeValue {
      value: None,
      duplicate: duplicate,
      span: DUMMY_SP
    }
  }

  pub fn simple() -> AttributeValue<T>
  {
    AttributeValue::new(DuplicateAttribute::simple(Warn))
  }

  pub fn update(self, cx: &ExtCtxt, value: T, span: Span) -> AttributeValue<T>
  {
    let mut this = self;
    if this.value.is_some() {
      this.duplicate.issue(cx, this.span, span);
    } else {
      this.value = Some(value);
      this.span = span;
    }
    this
  }

  pub fn has_value(&self) -> bool
  {
    self.value.is_some()
  }

  pub fn value_or(&self, default: T) -> T
  {
    match self.value {
      None => default,
      Some(ref value) => value.clone()
    }
  }

  pub fn span(&self) -> Span
  {
    self.span.clone()
  }
}

#[deriving(Clone)]
pub struct AttributeInfo
{
  pub name: InternedString,
  pub desc: &'static str,
  pub model: AttributeModel
}

impl AttributeInfo
{
  pub fn new(name: &'static str, desc: &'static str,
    model: AttributeModel) -> AttributeInfo
  {
    AttributeInfo {
      name: InternedString::new(name),
      desc: desc,
      model: model
    }
  }

  pub fn simple(name: &'static str, desc: &'static str) -> AttributeInfo
  {
    AttributeInfo::new(name, desc, UnitValue(AttributeValue::simple()))
  }

  pub fn update(self, model: AttributeModel) -> AttributeInfo
  {
    let mut this = self;
    this.model = model;
    this
  }

  pub fn plain_value<'a>(&'a self) -> &'a AttributeValue<()>
  {
    match self.model {
      UnitValue(ref v) => v,
      _ => fail!("No plain value for the current attribute.")
    }
  }

  pub fn sub_model<'a>(&'a self) -> &'a AttributeArray
  {
    match self.model {
      SubAttribute(ref array) => array,
      _ => fail!("No sub value for the current attribute.")
    }
  }

  pub fn key_value<'a>(&'a self) -> &'a AttributeLitModel
  {
    match self.model {
      KeyValue(ref lit) => lit,
      _ => fail!("No key value for the current attribute.")
    }
  }
}

#[deriving(Clone)]
pub enum AttributeModel
{
  UnitValue(AttributeValue<()>),
  KeyValue(AttributeLitModel),
  SubAttribute(AttributeArray)
}

#[deriving(Clone)]
pub enum AttributeLitModel
{
  MLitStr(AttributeValue<(InternedString, StrStyle)>),
  MLitBinary(AttributeValue<Rc<Vec<u8>>>),
  MLitByte(AttributeValue<u8>),
  MLitChar(AttributeValue<char>),
  MLitInt(AttributeValue<(u64, LitIntType)>),
  MLitFloat(AttributeValue<(InternedString, FloatTy)>),
  MLitFloatUnsuffixed(AttributeValue<InternedString>),
  MLitNil(AttributeValue<()>),
  MLitBool(AttributeValue<bool>)
}

pub type AttributeArray = Vec<AttributeInfo>;

pub mod access
{
  pub use super::*;
  pub fn by_name<'a>(array: &'a AttributeArray, name: &'static str) -> &'a AttributeInfo
  {
    let interned = InternedString::new(name);
    for info in array.iter() {
      if info.name == interned {
        return info;
      }
    }
    fail!("Try to get an attribute that doesn't exist.")
  }

  pub fn plain_value<'a>(array: &'a AttributeArray, name: &'static str) -> &'a AttributeValue<()>
  {
    by_name(array, name).plain_value()
  }

  pub fn sub_model<'a>(array: &'a AttributeArray, name: &'static str) -> &'a AttributeArray
  {
    by_name(array, name).sub_model()
  }

  pub fn lit_str<'a>(array: &'a AttributeArray, name: &'static str) -> Option<&'a AttributeValue<(InternedString, StrStyle)>>
  {
    match by_name(array, name).key_value() {
      &MLitStr(ref val) => Some(val),
      _ => None
    }
  }

  pub fn plain_value_or(array: &AttributeArray, name: &'static str, def: bool) -> bool
  {
    if plain_value(array, name).has_value() {
      true
    } else {
      def
    }
  }
}
// fn attribute_doc(&self)
// {
//   let mut doc = format!("Attribute `#[{}(<attribute list>)]`: {}\n",
//       self.root_name.get(), self.root_desc);
//   for info in self.infos.iter() {
//     doc.add(format!("  * `#[{}({})]`: {}\n",
//       self.root_name.get(), info.name, info.desc));
//   }
//   self.cx.parse_sess.span_diagnostic.handler.note(doc.as_slice());
// }

pub struct AttributeMerger<'a>
{
  cx: &'a ExtCtxt<'a>,
  duplicate: DuplicateAttribute
}

impl<'a> AttributeMerger<'a>
{
  pub fn new(cx: &'a ExtCtxt, duplicate: DuplicateAttribute) -> AttributeMerger<'a>
  {
    AttributeMerger {
      cx: cx,
      duplicate: duplicate
    }
  }

  pub fn merge(&self, info: AttributeInfo, info2: AttributeInfo) -> AttributeInfo
  {
    assert!(info.name == info2.name);
    let mut info = info;
    info.model = match (info.model, info2.model) {
      (UnitValue(val), UnitValue(val2)) => UnitValue(self.merge_value(val, val2)),
      (KeyValue(lit), KeyValue(lit2)) => KeyValue(self.merge_lit(lit, lit2)),
      (SubAttribute(sub), SubAttribute(sub2)) => SubAttribute(self.merge_sub_attr(sub, sub2)),
      _ => fail!("Mismatch between attribute models during merging.")
    };
    info
  }

  fn merge_value<T>(&self, val: AttributeValue<T>, val2: AttributeValue<T>) -> AttributeValue<T>
  {
    match (&val.value, &val2.value) {
      (&None, _) => val2,
      (_, &None) => val,
      (&Some(_), &Some(_)) => {
        self.duplicate.issue(self.cx, val.span, val2.span);
        val
      }
    }
  }

  fn merge_lit(&self, lit: AttributeLitModel, lit2: AttributeLitModel) -> AttributeLitModel
  {
    match (lit, lit2) {
      (MLitStr(val), MLitStr(val2)) => MLitStr(self.merge_value(val, val2)),
      (MLitBinary(val), MLitBinary(val2)) => MLitBinary(self.merge_value(val, val2)),
      (MLitByte(val), MLitByte(val2)) => MLitByte(self.merge_value(val, val2)),
      (MLitChar(val), MLitChar(val2)) => MLitChar(self.merge_value(val, val2)),
      (MLitInt(val), MLitInt(val2)) => MLitInt(self.merge_value(val, val2)),
      (MLitFloat(val), MLitFloat(val2)) => MLitFloat(self.merge_value(val, val2)),
      (MLitFloatUnsuffixed(val), MLitFloatUnsuffixed(val2)) => MLitFloatUnsuffixed(self.merge_value(val, val2)),
      (MLitNil(val), MLitNil(val2)) => MLitNil(self.merge_value(val, val2)),
      (MLitBool(val), MLitBool(val2)) => MLitBool(self.merge_value(val, val2)),
      _ => fail!("Mismatch between attribute models during merging.")
    }
  }

  fn merge_sub_attr(&self, sub1: AttributeArray, sub2: AttributeArray) -> AttributeArray
  {
    assert!(sub1.len() == sub2.len());
    sub1.move_iter()
      .zip(sub2.move_iter())
      .map(|(info, info2)| self.merge(info, info2))
      .collect()
  }
}

impl AttributeLitModel
{
  pub fn to_lit_printer(&self) -> LitTypePrinter
  {
    match *self {
      MLitStr(_) => PLitStr,
      MLitBinary(_) => PLitBinary,
      MLitByte(_) => PLitByte,
      MLitChar(_) => PLitChar,
      MLitInt(_) => PLitInt,
      MLitFloat(_) => PLitFloat,
      MLitFloatUnsuffixed(_) => PLitFloatUnsuffixed,
      MLitNil(_) => PLitNil,
      MLitBool(_) => PLitBool
    }
  }
}

pub fn lit_to_lit_printer(lit: &Lit_) -> LitTypePrinter
{
  match *lit {
    LitStr(_, _) => PLitStr,
    LitBinary(_) => PLitBinary,
    LitByte(_) => PLitByte,
    LitChar(_) => PLitChar,
    LitInt(_, _) => PLitInt,
    LitFloat(_, _) => PLitFloat,
    LitFloatUnsuffixed(_) => PLitFloatUnsuffixed,
    LitNil => PLitNil,
    LitBool(_) => PLitBool
  }
}

pub enum LitTypePrinter
{
  PLitStr,
  PLitBinary,
  PLitByte,
  PLitChar,
  PLitInt,
  PLitFloat,
  PLitFloatUnsuffixed,
  PLitNil,
  PLitBool
}

impl LitTypePrinter
{
  pub fn type_to_str(&self) -> &'static str
  {
    match *self {
      PLitStr => "string",
      PLitBinary => "binary",
      PLitByte => "byte",
      PLitChar => "char",
      PLitInt => "int",
      PLitFloat => "float",
      PLitFloatUnsuffixed => "unsuffixed float",
      PLitNil => "nil",
      PLitBool => "boolean"
    }
  }

  pub fn type_example_to_str(&self) -> &'static str
  {
    match *self {
      PLitStr => "\"hello world\"",
      PLitBinary => "0b01010101",
      PLitByte => "b'9'",
      PLitChar => "'a'",
      PLitInt => "38",
      PLitFloat => "0.01f32",
      PLitFloatUnsuffixed => "0.1",
      PLitNil => "()",
      PLitBool => "true"
    }
  }
}
<commit_msg>[Access] Don't return an optional, fail if not present.<commit_after>// Copyright 2014 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

pub use compile_error::*;
pub use syntax::parse::token::InternedString;
pub use syntax::ast::*;

use syntax::codemap::DUMMY_SP;
use std::rc::Rc;

#[deriving(Clone)]
pub struct AttributeValue<T>
{
  pub value: Option<T>,
  pub span: Span,
  duplicate: DuplicateAttribute
}

impl<T: Clone> AttributeValue<T>
{
  pub fn new(duplicate: DuplicateAttribute) -> AttributeValue<T>
  {
    AttributeValue {
      value: None,
      duplicate: duplicate,
      span: DUMMY_SP
    }
  }

  pub fn simple() -> AttributeValue<T>
  {
    AttributeValue::new(DuplicateAttribute::simple(Warn))
  }

  pub fn update(self, cx: &ExtCtxt, value: T, span: Span) -> AttributeValue<T>
  {
    let mut this = self;
    if this.value.is_some() {
      this.duplicate.issue(cx, this.span, span);
    } else {
      this.value = Some(value);
      this.span = span;
    }
    this
  }

  pub fn has_value(&self) -> bool
  {
    self.value.is_some()
  }

  pub fn value_or(&self, default: T) -> T
  {
    match self.value {
      None => default,
      Some(ref value) => value.clone()
    }
  }

  pub fn span(&self) -> Span
  {
    self.span.clone()
  }
}

#[deriving(Clone)]
pub struct AttributeInfo
{
  pub name: InternedString,
  pub desc: &'static str,
  pub model: AttributeModel
}

impl AttributeInfo
{
  pub fn new(name: &'static str, desc: &'static str,
    model: AttributeModel) -> AttributeInfo
  {
    AttributeInfo {
      name: InternedString::new(name),
      desc: desc,
      model: model
    }
  }

  pub fn simple(name: &'static str, desc: &'static str) -> AttributeInfo
  {
    AttributeInfo::new(name, desc, UnitValue(AttributeValue::simple()))
  }

  pub fn update(self, model: AttributeModel) -> AttributeInfo
  {
    let mut this = self;
    this.model = model;
    this
  }

  pub fn plain_value<'a>(&'a self) -> &'a AttributeValue<()>
  {
    match self.model {
      UnitValue(ref v) => v,
      _ => fail!("No plain value for the current attribute.")
    }
  }

  pub fn sub_model<'a>(&'a self) -> &'a AttributeArray
  {
    match self.model {
      SubAttribute(ref array) => array,
      _ => fail!("No sub value for the current attribute.")
    }
  }

  pub fn key_value<'a>(&'a self) -> &'a AttributeLitModel
  {
    match self.model {
      KeyValue(ref lit) => lit,
      _ => fail!("No key value for the current attribute.")
    }
  }
}

#[deriving(Clone)]
pub enum AttributeModel
{
  UnitValue(AttributeValue<()>),
  KeyValue(AttributeLitModel),
  SubAttribute(AttributeArray)
}

#[deriving(Clone)]
pub enum AttributeLitModel
{
  MLitStr(AttributeValue<(InternedString, StrStyle)>),
  MLitBinary(AttributeValue<Rc<Vec<u8>>>),
  MLitByte(AttributeValue<u8>),
  MLitChar(AttributeValue<char>),
  MLitInt(AttributeValue<(u64, LitIntType)>),
  MLitFloat(AttributeValue<(InternedString, FloatTy)>),
  MLitFloatUnsuffixed(AttributeValue<InternedString>),
  MLitNil(AttributeValue<()>),
  MLitBool(AttributeValue<bool>)
}

pub type AttributeArray = Vec<AttributeInfo>;

pub mod access
{
  pub use super::*;
  pub fn by_name<'a>(array: &'a AttributeArray, name: &'static str) -> &'a AttributeInfo
  {
    let interned = InternedString::new(name);
    for info in array.iter() {
      if info.name == interned {
        return info;
      }
    }
    fail!("Try to get an attribute that doesn't exist.")
  }

  pub fn plain_value<'a>(array: &'a AttributeArray, name: &'static str) -> &'a AttributeValue<()>
  {
    by_name(array, name).plain_value()
  }

  pub fn sub_model<'a>(array: &'a AttributeArray, name: &'static str) -> &'a AttributeArray
  {
    by_name(array, name).sub_model()
  }

  pub fn lit_str<'a>(array: &'a AttributeArray, name: &'static str) -> &'a AttributeValue<(InternedString, StrStyle)>
  {
    match by_name(array, name).key_value() {
      &MLitStr(ref val) => val,
      _ => fail!("No string literal available for this attribute.")
    }
  }

  pub fn plain_value_or(array: &AttributeArray, name: &'static str, def: bool) -> bool
  {
    if plain_value(array, name).has_value() {
      true
    } else {
      def
    }
  }
}
// fn attribute_doc(&self)
// {
//   let mut doc = format!("Attribute `#[{}(<attribute list>)]`: {}\n",
//       self.root_name.get(), self.root_desc);
//   for info in self.infos.iter() {
//     doc.add(format!("  * `#[{}({})]`: {}\n",
//       self.root_name.get(), info.name, info.desc));
//   }
//   self.cx.parse_sess.span_diagnostic.handler.note(doc.as_slice());
// }

pub struct AttributeMerger<'a>
{
  cx: &'a ExtCtxt<'a>,
  duplicate: DuplicateAttribute
}

impl<'a> AttributeMerger<'a>
{
  pub fn new(cx: &'a ExtCtxt, duplicate: DuplicateAttribute) -> AttributeMerger<'a>
  {
    AttributeMerger {
      cx: cx,
      duplicate: duplicate
    }
  }

  pub fn merge(&self, info: AttributeInfo, info2: AttributeInfo) -> AttributeInfo
  {
    assert!(info.name == info2.name);
    let mut info = info;
    info.model = match (info.model, info2.model) {
      (UnitValue(val), UnitValue(val2)) => UnitValue(self.merge_value(val, val2)),
      (KeyValue(lit), KeyValue(lit2)) => KeyValue(self.merge_lit(lit, lit2)),
      (SubAttribute(sub), SubAttribute(sub2)) => SubAttribute(self.merge_sub_attr(sub, sub2)),
      _ => fail!("Mismatch between attribute models during merging.")
    };
    info
  }

  fn merge_value<T>(&self, val: AttributeValue<T>, val2: AttributeValue<T>) -> AttributeValue<T>
  {
    match (&val.value, &val2.value) {
      (&None, _) => val2,
      (_, &None) => val,
      (&Some(_), &Some(_)) => {
        self.duplicate.issue(self.cx, val.span, val2.span);
        val
      }
    }
  }

  fn merge_lit(&self, lit: AttributeLitModel, lit2: AttributeLitModel) -> AttributeLitModel
  {
    match (lit, lit2) {
      (MLitStr(val), MLitStr(val2)) => MLitStr(self.merge_value(val, val2)),
      (MLitBinary(val), MLitBinary(val2)) => MLitBinary(self.merge_value(val, val2)),
      (MLitByte(val), MLitByte(val2)) => MLitByte(self.merge_value(val, val2)),
      (MLitChar(val), MLitChar(val2)) => MLitChar(self.merge_value(val, val2)),
      (MLitInt(val), MLitInt(val2)) => MLitInt(self.merge_value(val, val2)),
      (MLitFloat(val), MLitFloat(val2)) => MLitFloat(self.merge_value(val, val2)),
      (MLitFloatUnsuffixed(val), MLitFloatUnsuffixed(val2)) => MLitFloatUnsuffixed(self.merge_value(val, val2)),
      (MLitNil(val), MLitNil(val2)) => MLitNil(self.merge_value(val, val2)),
      (MLitBool(val), MLitBool(val2)) => MLitBool(self.merge_value(val, val2)),
      _ => fail!("Mismatch between attribute models during merging.")
    }
  }

  fn merge_sub_attr(&self, sub1: AttributeArray, sub2: AttributeArray) -> AttributeArray
  {
    assert!(sub1.len() == sub2.len());
    sub1.move_iter()
      .zip(sub2.move_iter())
      .map(|(info, info2)| self.merge(info, info2))
      .collect()
  }
}

impl AttributeLitModel
{
  pub fn to_lit_printer(&self) -> LitTypePrinter
  {
    match *self {
      MLitStr(_) => PLitStr,
      MLitBinary(_) => PLitBinary,
      MLitByte(_) => PLitByte,
      MLitChar(_) => PLitChar,
      MLitInt(_) => PLitInt,
      MLitFloat(_) => PLitFloat,
      MLitFloatUnsuffixed(_) => PLitFloatUnsuffixed,
      MLitNil(_) => PLitNil,
      MLitBool(_) => PLitBool
    }
  }
}

pub fn lit_to_lit_printer(lit: &Lit_) -> LitTypePrinter
{
  match *lit {
    LitStr(_, _) => PLitStr,
    LitBinary(_) => PLitBinary,
    LitByte(_) => PLitByte,
    LitChar(_) => PLitChar,
    LitInt(_, _) => PLitInt,
    LitFloat(_, _) => PLitFloat,
    LitFloatUnsuffixed(_) => PLitFloatUnsuffixed,
    LitNil => PLitNil,
    LitBool(_) => PLitBool
  }
}

pub enum LitTypePrinter
{
  PLitStr,
  PLitBinary,
  PLitByte,
  PLitChar,
  PLitInt,
  PLitFloat,
  PLitFloatUnsuffixed,
  PLitNil,
  PLitBool
}

impl LitTypePrinter
{
  pub fn type_to_str(&self) -> &'static str
  {
    match *self {
      PLitStr => "string",
      PLitBinary => "binary",
      PLitByte => "byte",
      PLitChar => "char",
      PLitInt => "int",
      PLitFloat => "float",
      PLitFloatUnsuffixed => "unsuffixed float",
      PLitNil => "nil",
      PLitBool => "boolean"
    }
  }

  pub fn type_example_to_str(&self) -> &'static str
  {
    match *self {
      PLitStr => "\"hello world\"",
      PLitBinary => "0b01010101",
      PLitByte => "b'9'",
      PLitChar => "'a'",
      PLitInt => "38",
      PLitFloat => "0.01f32",
      PLitFloatUnsuffixed => "0.1",
      PLitNil => "()",
      PLitBool => "true"
    }
  }
}
<|endoftext|>


<commit_before>//! This crates defines the trait resolution method and the type inference engine.
//!
//! - **Traits.** Trait resolution is implemented in the `traits` module.
//! - **Type inference.** The type inference code can be found in the `infer` module;
//!   this code handles low-level equality and subtyping operations. The
//!   type check pass in the compiler is found in the `librustc_typeck` crate.
//!
//! For more information about how rustc works, see the [rustc guide].
//!
//! [rustc guide]: https://rust-lang.github.io/rustc-guide/
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(drain_filter)]
#![feature(never_type)]
#![feature(range_is_empty)]
#![feature(in_band_lifetimes)]
#![feature(crate_visibility_modifier)]
#![recursion_limit = "512"]

#[macro_use]
extern crate rustc_macros;
#[macro_use]
extern crate rustc_data_structures;
#[macro_use]
extern crate log;
#[macro_use]
extern crate rustc;

pub mod infer;
pub mod traits;
<commit_msg>Gate macro use.<commit_after>//! This crates defines the trait resolution method and the type inference engine.
//!
//! - **Traits.** Trait resolution is implemented in the `traits` module.
//! - **Type inference.** The type inference code can be found in the `infer` module;
//!   this code handles low-level equality and subtyping operations. The
//!   type check pass in the compiler is found in the `librustc_typeck` crate.
//!
//! For more information about how rustc works, see the [rustc guide].
//!
//! [rustc guide]: https://rust-lang.github.io/rustc-guide/
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(drain_filter)]
#![feature(never_type)]
#![feature(range_is_empty)]
#![feature(in_band_lifetimes)]
#![feature(crate_visibility_modifier)]
#![recursion_limit = "512"]

#[macro_use]
extern crate rustc_macros;
#[cfg(target_arch = "x86_64")]
#[macro_use]
extern crate rustc_data_structures;
#[macro_use]
extern crate log;
#[macro_use]
extern crate rustc;

pub mod infer;
pub mod traits;
<|endoftext|>


<commit_before>// Copyright 2013-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.

//! Dynamic library facilities.
//!
//! A simple wrapper over the platform's dynamic library facilities

#![unstable(feature = "std_misc")]
#![allow(missing_docs)]

use prelude::v1::*;

use env;
use ffi::{CString, OsString};
use mem;
use path::{Path, PathBuf};

pub struct DynamicLibrary {
    handle: *mut u8
}

impl Drop for DynamicLibrary {
    fn drop(&mut self) {
        match dl::check_for_errors_in(|| {
            unsafe {
                dl::close(self.handle)
            }
        }) {
            Ok(()) => {},
            Err(str) => panic!("{}", str)
        }
    }
}

impl DynamicLibrary {
    // FIXME (#12938): Until DST lands, we cannot decompose &str into
    // & and str, so we cannot usefully take ToCStr arguments by
    // reference (without forcing an additional & around &str). So we
    // are instead temporarily adding an instance for &Path, so that
    // we can take ToCStr as owned. When DST lands, the &Path instance
    // should be removed, and arguments bound by ToCStr should be
    // passed by reference. (Here: in the `open` method.)

    /// Lazily open a dynamic library. When passed None it gives a
    /// handle to the calling process
    pub fn open(filename: Option<&Path>) -> Result<DynamicLibrary, String> {
        let maybe_library = dl::open(filename.map(|path| path.as_os_str()));

        // The dynamic library must not be constructed if there is
        // an error opening the library so the destructor does not
        // run.
        match maybe_library {
            Err(err) => Err(err),
            Ok(handle) => Ok(DynamicLibrary { handle: handle })
        }
    }

    /// Prepends a path to this process's search path for dynamic libraries
    pub fn prepend_search_path(path: &Path) {
        let mut search_path = DynamicLibrary::search_path();
        search_path.insert(0, path.to_path_buf());
        env::set_var(DynamicLibrary::envvar(), &DynamicLibrary::create_path(&search_path));
    }

    /// From a slice of paths, create a new vector which is suitable to be an
    /// environment variable for this platforms dylib search path.
    pub fn create_path(path: &[PathBuf]) -> OsString {
        let mut newvar = OsString::new();
        for (i, path) in path.iter().enumerate() {
            if i > 0 { newvar.push(DynamicLibrary::separator()); }
            newvar.push(path);
        }
        return newvar;
    }

    /// Returns the environment variable for this process's dynamic library
    /// search path
    pub fn envvar() -> &'static str {
        if cfg!(windows) {
            "PATH"
        } else if cfg!(target_os = "macos") {
            "DYLD_LIBRARY_PATH"
        } else {
            "LD_LIBRARY_PATH"
        }
    }

    fn separator() -> &'static str {
        if cfg!(windows) { ";" } else { ":" }
    }

    /// Returns the current search path for dynamic libraries being used by this
    /// process
    pub fn search_path() -> Vec<PathBuf> {
        match env::var_os(DynamicLibrary::envvar()) {
            Some(var) => env::split_paths(&var).collect(),
            None => Vec::new(),
        }
    }

    /// Accesses the value at the symbol of the dynamic library.
    pub unsafe fn symbol<T>(&self, symbol: &str) -> Result<*mut T, String> {
        // This function should have a lifetime constraint of 'a on
        // T but that feature is still unimplemented

        let raw_string = CString::new(symbol).unwrap();
        let maybe_symbol_value = dl::check_for_errors_in(|| {
            dl::symbol(self.handle, raw_string.as_ptr())
        });

        // The value must not be constructed if there is an error so
        // the destructor does not run.
        match maybe_symbol_value {
            Err(err) => Err(err),
            Ok(symbol_value) => Ok(mem::transmute(symbol_value))
        }
    }
}

#[cfg(all(test, not(target_os = "ios")))]
mod test {
    use super::*;
    use prelude::v1::*;
    use libc;
    use mem;
    use path::Path;

    #[test]
    #[cfg_attr(any(windows, target_os = "android"), ignore)] // FIXME #8818, #10379
    fn test_loading_cosine() {
        // The math library does not need to be loaded since it is already
        // statically linked in
        let libm = match DynamicLibrary::open(None) {
            Err(error) => panic!("Could not load self as module: {}", error),
            Ok(libm) => libm
        };

        let cosine: extern fn(libc::c_double) -> libc::c_double = unsafe {
            match libm.symbol("cos") {
                Err(error) => panic!("Could not load function cos: {}", error),
                Ok(cosine) => mem::transmute::<*mut u8, _>(cosine)
            }
        };

        let argument = 0.0;
        let expected_result = 1.0;
        let result = cosine(argument);
        if result != expected_result {
            panic!("cos({}) != {} but equaled {} instead", argument,
                   expected_result, result)
        }
    }

    #[test]
    #[cfg(any(target_os = "linux",
              target_os = "macos",
              target_os = "freebsd",
              target_os = "dragonfly",
              target_os = "bitrig",
              target_os = "openbsd"))]
    fn test_errors_do_not_crash() {
        // Open /dev/null as a library to get an error, and make sure
        // that only causes an error, and not a crash.
        let path = Path::new("/dev/null");
        match DynamicLibrary::open(Some(&path)) {
            Err(_) => {}
            Ok(_) => panic!("Successfully opened the empty library.")
        }
    }
}

#[cfg(any(target_os = "linux",
          target_os = "android",
          target_os = "macos",
          target_os = "ios",
          target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "bitrig",
          target_os = "openbsd"))]
mod dl {
    use prelude::v1::*;

    use ffi::{CStr, OsStr};
    use str;
    use libc;
    use ptr;

    pub fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> {
        check_for_errors_in(|| {
            unsafe {
                match filename {
                    Some(filename) => open_external(filename),
                    None => open_internal(),
                }
            }
        })
    }

    const LAZY: libc::c_int = 1;

    unsafe fn open_external(filename: &OsStr) -> *mut u8 {
        let s = filename.to_cstring().unwrap();
        dlopen(s.as_ptr(), LAZY) as *mut u8
    }

    unsafe fn open_internal() -> *mut u8 {
        dlopen(ptr::null(), LAZY) as *mut u8
    }

    pub fn check_for_errors_in<T, F>(f: F) -> Result<T, String> where
        F: FnOnce() -> T,
    {
        use sync::{StaticMutex, MUTEX_INIT};
        static LOCK: StaticMutex = MUTEX_INIT;
        unsafe {
            // dlerror isn't thread safe, so we need to lock around this entire
            // sequence
            let _guard = LOCK.lock();
            let _old_error = dlerror();

            let result = f();

            let last_error = dlerror() as *const _;
            let ret = if ptr::null() == last_error {
                Ok(result)
            } else {
                let s = CStr::from_ptr(last_error).to_bytes();
                Err(str::from_utf8(s).unwrap().to_string())
            };

            ret
        }
    }

    pub unsafe fn symbol(handle: *mut u8,
                         symbol: *const libc::c_char) -> *mut u8 {
        dlsym(handle as *mut libc::c_void, symbol) as *mut u8
    }
    pub unsafe fn close(handle: *mut u8) {
        dlclose(handle as *mut libc::c_void); ()
    }

    extern {
        fn dlopen(filename: *const libc::c_char,
                  flag: libc::c_int) -> *mut libc::c_void;
        fn dlerror() -> *mut libc::c_char;
        fn dlsym(handle: *mut libc::c_void,
                 symbol: *const libc::c_char) -> *mut libc::c_void;
        fn dlclose(handle: *mut libc::c_void) -> libc::c_int;
    }
}

#[cfg(target_os = "windows")]
mod dl {
    use prelude::v1::*;

    use ffi::OsStr;
    use libc;
    use libc::consts::os::extra::ERROR_CALL_NOT_IMPLEMENTED;
    use sys::os;
    use os::windows::prelude::*;
    use ptr;
    use sys::c::compat::kernel32::SetThreadErrorMode;

    pub fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> {
        // disable "dll load failed" error dialog.
        let mut use_thread_mode = true;
        let prev_error_mode = unsafe {
            // SEM_FAILCRITICALERRORS 0x01
            let new_error_mode = 1;
            let mut prev_error_mode = 0;
            // Windows >= 7 supports thread error mode.
            let result = SetThreadErrorMode(new_error_mode, &mut prev_error_mode);
            if result == 0 {
                let err = os::errno();
                if err as libc::c_int == ERROR_CALL_NOT_IMPLEMENTED {
                    use_thread_mode = false;
                    // SetThreadErrorMode not found. use fallback solution:
                    // SetErrorMode() Note that SetErrorMode is process-wide so
                    // this can cause race condition!  However, since even
                    // Windows APIs do not care of such problem (#20650), we
                    // just assume SetErrorMode race is not a great deal.
                    prev_error_mode = SetErrorMode(new_error_mode);
                }
            }
            prev_error_mode
        };

        unsafe {
            SetLastError(0);
        }

        let result = match filename {
            Some(filename) => {
                let filename_str: Vec<_> =
                    filename.encode_wide().chain(Some(0).into_iter()).collect();
                let result = unsafe {
                    LoadLibraryW(filename_str.as_ptr() as *const libc::c_void)
                };
                // beware: Vec/String may change errno during drop!
                // so we get error here.
                if result == ptr::null_mut() {
                    let errno = os::errno();
                    Err(os::error_string(errno))
                } else {
                    Ok(result as *mut u8)
                }
            }
            None => {
                let mut handle = ptr::null_mut();
                let succeeded = unsafe {
                    GetModuleHandleExW(0 as libc::DWORD, ptr::null(), &mut handle)
                };
                if succeeded == libc::FALSE {
                    let errno = os::errno();
                    Err(os::error_string(errno))
                } else {
                    Ok(handle as *mut u8)
                }
            }
        };

        unsafe {
            if use_thread_mode {
                SetThreadErrorMode(prev_error_mode, ptr::null_mut());
            } else {
                SetErrorMode(prev_error_mode);
            }
        }

        result
    }

    pub fn check_for_errors_in<T, F>(f: F) -> Result<T, String> where
        F: FnOnce() -> T,
    {
        unsafe {
            SetLastError(0);

            let result = f();

            let error = os::errno();
            if 0 == error {
                Ok(result)
            } else {
                Err(format!("Error code {}", error))
            }
        }
    }

    pub unsafe fn symbol(handle: *mut u8, symbol: *const libc::c_char) -> *mut u8 {
        GetProcAddress(handle as *mut libc::c_void, symbol) as *mut u8
    }
    pub unsafe fn close(handle: *mut u8) {
        FreeLibrary(handle as *mut libc::c_void); ()
    }

    #[allow(non_snake_case)]
    extern "system" {
        fn SetLastError(error: libc::size_t);
        fn LoadLibraryW(name: *const libc::c_void) -> *mut libc::c_void;
        fn GetModuleHandleExW(dwFlags: libc::DWORD, name: *const u16,
                              handle: *mut *mut libc::c_void) -> libc::BOOL;
        fn GetProcAddress(handle: *mut libc::c_void,
                          name: *const libc::c_char) -> *mut libc::c_void;
        fn FreeLibrary(handle: *mut libc::c_void);
        fn SetErrorMode(uMode: libc::c_uint) -> libc::c_uint;
    }
}
<commit_msg>Remove stale comment<commit_after>// Copyright 2013-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.

//! Dynamic library facilities.
//!
//! A simple wrapper over the platform's dynamic library facilities

#![unstable(feature = "std_misc")]
#![allow(missing_docs)]

use prelude::v1::*;

use env;
use ffi::{CString, OsString};
use mem;
use path::{Path, PathBuf};

pub struct DynamicLibrary {
    handle: *mut u8
}

impl Drop for DynamicLibrary {
    fn drop(&mut self) {
        match dl::check_for_errors_in(|| {
            unsafe {
                dl::close(self.handle)
            }
        }) {
            Ok(()) => {},
            Err(str) => panic!("{}", str)
        }
    }
}

impl DynamicLibrary {
    /// Lazily open a dynamic library. When passed None it gives a
    /// handle to the calling process
    pub fn open(filename: Option<&Path>) -> Result<DynamicLibrary, String> {
        let maybe_library = dl::open(filename.map(|path| path.as_os_str()));

        // The dynamic library must not be constructed if there is
        // an error opening the library so the destructor does not
        // run.
        match maybe_library {
            Err(err) => Err(err),
            Ok(handle) => Ok(DynamicLibrary { handle: handle })
        }
    }

    /// Prepends a path to this process's search path for dynamic libraries
    pub fn prepend_search_path(path: &Path) {
        let mut search_path = DynamicLibrary::search_path();
        search_path.insert(0, path.to_path_buf());
        env::set_var(DynamicLibrary::envvar(), &DynamicLibrary::create_path(&search_path));
    }

    /// From a slice of paths, create a new vector which is suitable to be an
    /// environment variable for this platforms dylib search path.
    pub fn create_path(path: &[PathBuf]) -> OsString {
        let mut newvar = OsString::new();
        for (i, path) in path.iter().enumerate() {
            if i > 0 { newvar.push(DynamicLibrary::separator()); }
            newvar.push(path);
        }
        return newvar;
    }

    /// Returns the environment variable for this process's dynamic library
    /// search path
    pub fn envvar() -> &'static str {
        if cfg!(windows) {
            "PATH"
        } else if cfg!(target_os = "macos") {
            "DYLD_LIBRARY_PATH"
        } else {
            "LD_LIBRARY_PATH"
        }
    }

    fn separator() -> &'static str {
        if cfg!(windows) { ";" } else { ":" }
    }

    /// Returns the current search path for dynamic libraries being used by this
    /// process
    pub fn search_path() -> Vec<PathBuf> {
        match env::var_os(DynamicLibrary::envvar()) {
            Some(var) => env::split_paths(&var).collect(),
            None => Vec::new(),
        }
    }

    /// Accesses the value at the symbol of the dynamic library.
    pub unsafe fn symbol<T>(&self, symbol: &str) -> Result<*mut T, String> {
        // This function should have a lifetime constraint of 'a on
        // T but that feature is still unimplemented

        let raw_string = CString::new(symbol).unwrap();
        let maybe_symbol_value = dl::check_for_errors_in(|| {
            dl::symbol(self.handle, raw_string.as_ptr())
        });

        // The value must not be constructed if there is an error so
        // the destructor does not run.
        match maybe_symbol_value {
            Err(err) => Err(err),
            Ok(symbol_value) => Ok(mem::transmute(symbol_value))
        }
    }
}

#[cfg(all(test, not(target_os = "ios")))]
mod test {
    use super::*;
    use prelude::v1::*;
    use libc;
    use mem;
    use path::Path;

    #[test]
    #[cfg_attr(any(windows, target_os = "android"), ignore)] // FIXME #8818, #10379
    fn test_loading_cosine() {
        // The math library does not need to be loaded since it is already
        // statically linked in
        let libm = match DynamicLibrary::open(None) {
            Err(error) => panic!("Could not load self as module: {}", error),
            Ok(libm) => libm
        };

        let cosine: extern fn(libc::c_double) -> libc::c_double = unsafe {
            match libm.symbol("cos") {
                Err(error) => panic!("Could not load function cos: {}", error),
                Ok(cosine) => mem::transmute::<*mut u8, _>(cosine)
            }
        };

        let argument = 0.0;
        let expected_result = 1.0;
        let result = cosine(argument);
        if result != expected_result {
            panic!("cos({}) != {} but equaled {} instead", argument,
                   expected_result, result)
        }
    }

    #[test]
    #[cfg(any(target_os = "linux",
              target_os = "macos",
              target_os = "freebsd",
              target_os = "dragonfly",
              target_os = "bitrig",
              target_os = "openbsd"))]
    fn test_errors_do_not_crash() {
        // Open /dev/null as a library to get an error, and make sure
        // that only causes an error, and not a crash.
        let path = Path::new("/dev/null");
        match DynamicLibrary::open(Some(&path)) {
            Err(_) => {}
            Ok(_) => panic!("Successfully opened the empty library.")
        }
    }
}

#[cfg(any(target_os = "linux",
          target_os = "android",
          target_os = "macos",
          target_os = "ios",
          target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "bitrig",
          target_os = "openbsd"))]
mod dl {
    use prelude::v1::*;

    use ffi::{CStr, OsStr};
    use str;
    use libc;
    use ptr;

    pub fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> {
        check_for_errors_in(|| {
            unsafe {
                match filename {
                    Some(filename) => open_external(filename),
                    None => open_internal(),
                }
            }
        })
    }

    const LAZY: libc::c_int = 1;

    unsafe fn open_external(filename: &OsStr) -> *mut u8 {
        let s = filename.to_cstring().unwrap();
        dlopen(s.as_ptr(), LAZY) as *mut u8
    }

    unsafe fn open_internal() -> *mut u8 {
        dlopen(ptr::null(), LAZY) as *mut u8
    }

    pub fn check_for_errors_in<T, F>(f: F) -> Result<T, String> where
        F: FnOnce() -> T,
    {
        use sync::{StaticMutex, MUTEX_INIT};
        static LOCK: StaticMutex = MUTEX_INIT;
        unsafe {
            // dlerror isn't thread safe, so we need to lock around this entire
            // sequence
            let _guard = LOCK.lock();
            let _old_error = dlerror();

            let result = f();

            let last_error = dlerror() as *const _;
            let ret = if ptr::null() == last_error {
                Ok(result)
            } else {
                let s = CStr::from_ptr(last_error).to_bytes();
                Err(str::from_utf8(s).unwrap().to_string())
            };

            ret
        }
    }

    pub unsafe fn symbol(handle: *mut u8,
                         symbol: *const libc::c_char) -> *mut u8 {
        dlsym(handle as *mut libc::c_void, symbol) as *mut u8
    }
    pub unsafe fn close(handle: *mut u8) {
        dlclose(handle as *mut libc::c_void); ()
    }

    extern {
        fn dlopen(filename: *const libc::c_char,
                  flag: libc::c_int) -> *mut libc::c_void;
        fn dlerror() -> *mut libc::c_char;
        fn dlsym(handle: *mut libc::c_void,
                 symbol: *const libc::c_char) -> *mut libc::c_void;
        fn dlclose(handle: *mut libc::c_void) -> libc::c_int;
    }
}

#[cfg(target_os = "windows")]
mod dl {
    use prelude::v1::*;

    use ffi::OsStr;
    use libc;
    use libc::consts::os::extra::ERROR_CALL_NOT_IMPLEMENTED;
    use sys::os;
    use os::windows::prelude::*;
    use ptr;
    use sys::c::compat::kernel32::SetThreadErrorMode;

    pub fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> {
        // disable "dll load failed" error dialog.
        let mut use_thread_mode = true;
        let prev_error_mode = unsafe {
            // SEM_FAILCRITICALERRORS 0x01
            let new_error_mode = 1;
            let mut prev_error_mode = 0;
            // Windows >= 7 supports thread error mode.
            let result = SetThreadErrorMode(new_error_mode, &mut prev_error_mode);
            if result == 0 {
                let err = os::errno();
                if err as libc::c_int == ERROR_CALL_NOT_IMPLEMENTED {
                    use_thread_mode = false;
                    // SetThreadErrorMode not found. use fallback solution:
                    // SetErrorMode() Note that SetErrorMode is process-wide so
                    // this can cause race condition!  However, since even
                    // Windows APIs do not care of such problem (#20650), we
                    // just assume SetErrorMode race is not a great deal.
                    prev_error_mode = SetErrorMode(new_error_mode);
                }
            }
            prev_error_mode
        };

        unsafe {
            SetLastError(0);
        }

        let result = match filename {
            Some(filename) => {
                let filename_str: Vec<_> =
                    filename.encode_wide().chain(Some(0).into_iter()).collect();
                let result = unsafe {
                    LoadLibraryW(filename_str.as_ptr() as *const libc::c_void)
                };
                // beware: Vec/String may change errno during drop!
                // so we get error here.
                if result == ptr::null_mut() {
                    let errno = os::errno();
                    Err(os::error_string(errno))
                } else {
                    Ok(result as *mut u8)
                }
            }
            None => {
                let mut handle = ptr::null_mut();
                let succeeded = unsafe {
                    GetModuleHandleExW(0 as libc::DWORD, ptr::null(), &mut handle)
                };
                if succeeded == libc::FALSE {
                    let errno = os::errno();
                    Err(os::error_string(errno))
                } else {
                    Ok(handle as *mut u8)
                }
            }
        };

        unsafe {
            if use_thread_mode {
                SetThreadErrorMode(prev_error_mode, ptr::null_mut());
            } else {
                SetErrorMode(prev_error_mode);
            }
        }

        result
    }

    pub fn check_for_errors_in<T, F>(f: F) -> Result<T, String> where
        F: FnOnce() -> T,
    {
        unsafe {
            SetLastError(0);

            let result = f();

            let error = os::errno();
            if 0 == error {
                Ok(result)
            } else {
                Err(format!("Error code {}", error))
            }
        }
    }

    pub unsafe fn symbol(handle: *mut u8, symbol: *const libc::c_char) -> *mut u8 {
        GetProcAddress(handle as *mut libc::c_void, symbol) as *mut u8
    }
    pub unsafe fn close(handle: *mut u8) {
        FreeLibrary(handle as *mut libc::c_void); ()
    }

    #[allow(non_snake_case)]
    extern "system" {
        fn SetLastError(error: libc::size_t);
        fn LoadLibraryW(name: *const libc::c_void) -> *mut libc::c_void;
        fn GetModuleHandleExW(dwFlags: libc::DWORD, name: *const u16,
                              handle: *mut *mut libc::c_void) -> libc::BOOL;
        fn GetProcAddress(handle: *mut libc::c_void,
                          name: *const libc::c_char) -> *mut libc::c_void;
        fn FreeLibrary(handle: *mut libc::c_void);
        fn SetErrorMode(uMode: libc::c_uint) -> libc::c_uint;
    }
}
<|endoftext|>


<commit_before>use crate::ty::subst::SubstsRef;
use crate::ty::{self, Ty, TyCtxt};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_macros::HashStable;
use rustc_span::Span;

#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
pub enum PointerCast {
    /// Go from a fn-item type to a fn-pointer type.
    ReifyFnPointer,

    /// Go from a safe fn pointer to an unsafe fn pointer.
    UnsafeFnPointer,

    /// Go from a non-capturing closure to an fn pointer or an unsafe fn pointer.
    /// It cannot convert a closure that requires unsafe.
    ClosureFnPointer(hir::Unsafety),

    /// Go from a mut raw pointer to a const raw pointer.
    MutToConstPointer,

    /// Go from `*const [T; N]` to `*const T`
    ArrayToPointer,

    /// Unsize a pointer/reference value, e.g., `&[T; n]` to
    /// `&[T]`. Note that the source could be a thin or fat pointer.
    /// This will do things like convert thin pointers to fat
    /// pointers, or convert structs containing thin pointers to
    /// structs containing fat pointers, or convert between fat
    /// pointers. We don't store the details of how the transform is
    /// done (in fact, we don't know that, because it might depend on
    /// the precise type parameters). We just store the target
    /// type. Codegen backends and miri figure out what has to be done
    /// based on the precise source/target type at hand.
    Unsize,
}

/// Represents coercing a value to a different type of value.
///
/// We transform values by following a number of `Adjust` steps in order.
/// See the documentation on variants of `Adjust` for more details.
///
/// Here are some common scenarios:
///
/// 1. The simplest cases are where a pointer is not adjusted fat vs thin.
///    Here the pointer will be dereferenced N times (where a dereference can
///    happen to raw or borrowed pointers or any smart pointer which implements
///    Deref, including Box<_>). The types of dereferences is given by
///    `autoderefs`. It can then be auto-referenced zero or one times, indicated
///    by `autoref`, to either a raw or borrowed pointer. In these cases unsize is
///    `false`.
///
/// 2. A thin-to-fat coercion involves unsizing the underlying data. We start
///    with a thin pointer, deref a number of times, unsize the underlying data,
///    then autoref. The 'unsize' phase may change a fixed length array to a
///    dynamically sized one, a concrete object to a trait object, or statically
///    sized struct to a dynamically sized one. E.g., &[i32; 4] -> &[i32] is
///    represented by:
///
///    ```
///    Deref(None) -> [i32; 4],
///    Borrow(AutoBorrow::Ref) -> &[i32; 4],
///    Unsize -> &[i32],
///    ```
///
///    Note that for a struct, the 'deep' unsizing of the struct is not recorded.
///    E.g., `struct Foo<T> { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]>
///    The autoderef and -ref are the same as in the above example, but the type
///    stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about
///    the underlying conversions from `[i32; 4]` to `[i32]`.
///
/// 3. Coercing a `Box<T>` to `Box<dyn Trait>` is an interesting special case. In
///    that case, we have the pointer we need coming in, so there are no
///    autoderefs, and no autoref. Instead we just do the `Unsize` transformation.
///    At some point, of course, `Box` should move out of the compiler, in which
///    case this is analogous to transforming a struct. E.g., Box<[i32; 4]> ->
///    Box<[i32]> is an `Adjust::Unsize` with the target `Box<[i32]>`.
#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
pub struct Adjustment<'tcx> {
    pub kind: Adjust<'tcx>,
    pub target: Ty<'tcx>,
}

impl Adjustment<'tcx> {
    pub fn is_region_borrow(&self) -> bool {
        matches!(self.kind, Adjust::Borrow(AutoBorrow::Ref(..)))
    }
}

#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
pub enum Adjust<'tcx> {
    /// Go from ! to any type.
    NeverToAny,

    /// Dereference once, producing a place.
    Deref(Option<OverloadedDeref<'tcx>>),

    /// Take the address and produce either a `&` or `*` pointer.
    Borrow(AutoBorrow<'tcx>),

    Pointer(PointerCast),
}

/// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)`
/// call, with the signature `&'a T -> &'a U` or `&'a mut T -> &'a mut U`.
/// The target type is `U` in both cases, with the region and mutability
/// being those shared by both the receiver and the returned reference.
#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
pub struct OverloadedDeref<'tcx> {
    pub region: ty::Region<'tcx>,
    pub mutbl: hir::Mutability,
    /// The `Span` associated with the field access or method call
    /// that triggered this overloaded deref.
    pub span: Span,
}

impl<'tcx> OverloadedDeref<'tcx> {
    pub fn method_call(&self, tcx: TyCtxt<'tcx>, source: Ty<'tcx>) -> (DefId, SubstsRef<'tcx>) {
        let trait_def_id = match self.mutbl {
            hir::Mutability::Not => tcx.require_lang_item(LangItem::Deref, None),
            hir::Mutability::Mut => tcx.require_lang_item(LangItem::DerefMut, None),
        };
        let method_def_id = tcx
            .associated_items(trait_def_id)
            .in_definition_order()
            .find(|m| m.kind == ty::AssocKind::Fn)
            .unwrap()
            .def_id;
        (method_def_id, tcx.mk_substs_trait(source, &[]))
    }
}

/// At least for initial deployment, we want to limit two-phase borrows to
/// only a few specific cases. Right now, those are mostly "things that desugar"
/// into method calls:
/// - using `x.some_method()` syntax, where some_method takes `&mut self`,
/// - using `Foo::some_method(&mut x, ...)` syntax,
/// - binary assignment operators (`+=`, `-=`, `*=`, etc.).
/// Anything else should be rejected until generalized two-phase borrow support
/// is implemented. Right now, dataflow can't handle the general case where there
/// is more than one use of a mutable borrow, and we don't want to accept too much
/// new code via two-phase borrows, so we try to limit where we create two-phase
/// capable mutable borrows.
/// See #49434 for tracking.
#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
pub enum AllowTwoPhase {
    Yes,
    No,
}

#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
pub enum AutoBorrowMutability {
    Mut { allow_two_phase_borrow: AllowTwoPhase },
    Not,
}

impl From<AutoBorrowMutability> for hir::Mutability {
    fn from(m: AutoBorrowMutability) -> Self {
        match m {
            AutoBorrowMutability::Mut { .. } => hir::Mutability::Mut,
            AutoBorrowMutability::Not => hir::Mutability::Not,
        }
    }
}

#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
pub enum AutoBorrow<'tcx> {
    /// Converts from T to &T.
    Ref(ty::Region<'tcx>, AutoBorrowMutability),

    /// Converts from T to *T.
    RawPtr(hir::Mutability),
}

/// Information for `CoerceUnsized` impls, storing information we
/// have computed about the coercion.
///
/// This struct can be obtained via the `coerce_impl_info` query.
/// Demanding this struct also has the side-effect of reporting errors
/// for inappropriate impls.
#[derive(Clone, Copy, TyEncodable, TyDecodable, Debug, HashStable)]
pub struct CoerceUnsizedInfo {
    /// If this is a "custom coerce" impl, then what kind of custom
    /// coercion is it? This applies to impls of `CoerceUnsized` for
    /// structs, primarily, where we store a bit of info about which
    /// fields need to be coerced.
    pub custom_kind: Option<CustomCoerceUnsized>,
}

#[derive(Clone, Copy, TyEncodable, TyDecodable, Debug, HashStable)]
pub enum CustomCoerceUnsized {
    /// Records the index of the field being coerced.
    Struct(usize),
}
<commit_msg>Rollup merge of #85650 - scottmcm:adjust-adjustment-docs, r=jyn514<commit_after>use crate::ty::subst::SubstsRef;
use crate::ty::{self, Ty, TyCtxt};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_macros::HashStable;
use rustc_span::Span;

#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
pub enum PointerCast {
    /// Go from a fn-item type to a fn-pointer type.
    ReifyFnPointer,

    /// Go from a safe fn pointer to an unsafe fn pointer.
    UnsafeFnPointer,

    /// Go from a non-capturing closure to an fn pointer or an unsafe fn pointer.
    /// It cannot convert a closure that requires unsafe.
    ClosureFnPointer(hir::Unsafety),

    /// Go from a mut raw pointer to a const raw pointer.
    MutToConstPointer,

    /// Go from `*const [T; N]` to `*const T`
    ArrayToPointer,

    /// Unsize a pointer/reference value, e.g., `&[T; n]` to
    /// `&[T]`. Note that the source could be a thin or fat pointer.
    /// This will do things like convert thin pointers to fat
    /// pointers, or convert structs containing thin pointers to
    /// structs containing fat pointers, or convert between fat
    /// pointers. We don't store the details of how the transform is
    /// done (in fact, we don't know that, because it might depend on
    /// the precise type parameters). We just store the target
    /// type. Codegen backends and miri figure out what has to be done
    /// based on the precise source/target type at hand.
    Unsize,
}

/// Represents coercing a value to a different type of value.
///
/// We transform values by following a number of `Adjust` steps in order.
/// See the documentation on variants of `Adjust` for more details.
///
/// Here are some common scenarios:
///
/// 1. The simplest cases are where a pointer is not adjusted fat vs thin.
///    Here the pointer will be dereferenced N times (where a dereference can
///    happen to raw or borrowed pointers or any smart pointer which implements
///    `Deref`, including `Box<_>`). The types of dereferences is given by
///    `autoderefs`. It can then be auto-referenced zero or one times, indicated
///    by `autoref`, to either a raw or borrowed pointer. In these cases unsize is
///    `false`.
///
/// 2. A thin-to-fat coercion involves unsizing the underlying data. We start
///    with a thin pointer, deref a number of times, unsize the underlying data,
///    then autoref. The 'unsize' phase may change a fixed length array to a
///    dynamically sized one, a concrete object to a trait object, or statically
///    sized struct to a dynamically sized one. E.g., `&[i32; 4]` -> `&[i32]` is
///    represented by:
///
///    ```
///    Deref(None) -> [i32; 4],
///    Borrow(AutoBorrow::Ref) -> &[i32; 4],
///    Unsize -> &[i32],
///    ```
///
///    Note that for a struct, the 'deep' unsizing of the struct is not recorded.
///    E.g., `struct Foo<T> { x: T }` we can coerce `&Foo<[i32; 4]>` to `&Foo<[i32]>`
///    The autoderef and -ref are the same as in the above example, but the type
///    stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about
///    the underlying conversions from `[i32; 4]` to `[i32]`.
///
/// 3. Coercing a `Box<T>` to `Box<dyn Trait>` is an interesting special case. In
///    that case, we have the pointer we need coming in, so there are no
///    autoderefs, and no autoref. Instead we just do the `Unsize` transformation.
///    At some point, of course, `Box` should move out of the compiler, in which
///    case this is analogous to transforming a struct. E.g., `Box<[i32; 4]>` ->
///    `Box<[i32]>` is an `Adjust::Unsize` with the target `Box<[i32]>`.
#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
pub struct Adjustment<'tcx> {
    pub kind: Adjust<'tcx>,
    pub target: Ty<'tcx>,
}

impl Adjustment<'tcx> {
    pub fn is_region_borrow(&self) -> bool {
        matches!(self.kind, Adjust::Borrow(AutoBorrow::Ref(..)))
    }
}

#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
pub enum Adjust<'tcx> {
    /// Go from ! to any type.
    NeverToAny,

    /// Dereference once, producing a place.
    Deref(Option<OverloadedDeref<'tcx>>),

    /// Take the address and produce either a `&` or `*` pointer.
    Borrow(AutoBorrow<'tcx>),

    Pointer(PointerCast),
}

/// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)`
/// call, with the signature `&'a T -> &'a U` or `&'a mut T -> &'a mut U`.
/// The target type is `U` in both cases, with the region and mutability
/// being those shared by both the receiver and the returned reference.
#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
pub struct OverloadedDeref<'tcx> {
    pub region: ty::Region<'tcx>,
    pub mutbl: hir::Mutability,
    /// The `Span` associated with the field access or method call
    /// that triggered this overloaded deref.
    pub span: Span,
}

impl<'tcx> OverloadedDeref<'tcx> {
    pub fn method_call(&self, tcx: TyCtxt<'tcx>, source: Ty<'tcx>) -> (DefId, SubstsRef<'tcx>) {
        let trait_def_id = match self.mutbl {
            hir::Mutability::Not => tcx.require_lang_item(LangItem::Deref, None),
            hir::Mutability::Mut => tcx.require_lang_item(LangItem::DerefMut, None),
        };
        let method_def_id = tcx
            .associated_items(trait_def_id)
            .in_definition_order()
            .find(|m| m.kind == ty::AssocKind::Fn)
            .unwrap()
            .def_id;
        (method_def_id, tcx.mk_substs_trait(source, &[]))
    }
}

/// At least for initial deployment, we want to limit two-phase borrows to
/// only a few specific cases. Right now, those are mostly "things that desugar"
/// into method calls:
/// - using `x.some_method()` syntax, where some_method takes `&mut self`,
/// - using `Foo::some_method(&mut x, ...)` syntax,
/// - binary assignment operators (`+=`, `-=`, `*=`, etc.).
/// Anything else should be rejected until generalized two-phase borrow support
/// is implemented. Right now, dataflow can't handle the general case where there
/// is more than one use of a mutable borrow, and we don't want to accept too much
/// new code via two-phase borrows, so we try to limit where we create two-phase
/// capable mutable borrows.
/// See #49434 for tracking.
#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
pub enum AllowTwoPhase {
    Yes,
    No,
}

#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
pub enum AutoBorrowMutability {
    Mut { allow_two_phase_borrow: AllowTwoPhase },
    Not,
}

impl From<AutoBorrowMutability> for hir::Mutability {
    fn from(m: AutoBorrowMutability) -> Self {
        match m {
            AutoBorrowMutability::Mut { .. } => hir::Mutability::Mut,
            AutoBorrowMutability::Not => hir::Mutability::Not,
        }
    }
}

#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
pub enum AutoBorrow<'tcx> {
    /// Converts from T to &T.
    Ref(ty::Region<'tcx>, AutoBorrowMutability),

    /// Converts from T to *T.
    RawPtr(hir::Mutability),
}

/// Information for `CoerceUnsized` impls, storing information we
/// have computed about the coercion.
///
/// This struct can be obtained via the `coerce_impl_info` query.
/// Demanding this struct also has the side-effect of reporting errors
/// for inappropriate impls.
#[derive(Clone, Copy, TyEncodable, TyDecodable, Debug, HashStable)]
pub struct CoerceUnsizedInfo {
    /// If this is a "custom coerce" impl, then what kind of custom
    /// coercion is it? This applies to impls of `CoerceUnsized` for
    /// structs, primarily, where we store a bit of info about which
    /// fields need to be coerced.
    pub custom_kind: Option<CustomCoerceUnsized>,
}

#[derive(Clone, Copy, TyEncodable, TyDecodable, Debug, HashStable)]
pub enum CustomCoerceUnsized {
    /// Records the index of the field being coerced.
    Struct(usize),
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![deny(missing_docs)]

//! Base classes to work with IDL callbacks.

use dom::bindings::global::global_object_for_js_object;
use dom::bindings::js::JSRef;
use dom::bindings::utils::Reflectable;
use js::jsapi::{JSContext, JSObject, JS_WrapObject, JS_ObjectIsCallable, JS_GetGlobalObject};
use js::jsapi::{JS_GetProperty, JS_IsExceptionPending, JS_ReportPendingException};
use js::jsapi::{JS_GetPendingException};
use js::jsval::{JSVal, UndefinedValue};
use js::rust::with_compartment;

use std::ptr;

/// The exception handling used for a call.
#[deriving(Copy, PartialEq)]
pub enum ExceptionHandling {
    /// Report any exception and don't throw it to the caller code.
    Report,
    /// Throw any exception to the caller code.
    Rethrow
}

/// A common base class for representing IDL callback function types.
#[deriving(Copy, Clone,PartialEq)]
#[jstraceable]
pub struct CallbackFunction {
    object: CallbackObject
}

impl CallbackFunction {
    /// Create a new `CallbackFunction` for this object.
    pub fn new(callback: *mut JSObject) -> CallbackFunction {
        CallbackFunction {
            object: CallbackObject {
                callback: callback
            }
        }
    }
}

/// A common base class for representing IDL callback interface types.
#[deriving(Copy, Clone,PartialEq)]
#[jstraceable]
pub struct CallbackInterface {
    object: CallbackObject
}

/// A common base class for representing IDL callback function and
/// callback interface types.
#[allow(raw_pointer_deriving)]
#[deriving(Copy, Clone,PartialEq)]
#[jstraceable]
struct CallbackObject {
    /// The underlying `JSObject`.
    callback: *mut JSObject,
}

/// A trait to be implemented by concrete IDL callback function and
/// callback interface types.
pub trait CallbackContainer {
    /// Create a new CallbackContainer object for the given `JSObject`.
    fn new(callback: *mut JSObject) -> Self;
    /// Returns the underlying `JSObject`.
    fn callback(&self) -> *mut JSObject;
}

impl CallbackInterface {
    /// Returns the underlying `JSObject`.
    pub fn callback(&self) -> *mut JSObject {
        self.object.callback
    }
}

impl CallbackFunction {
    /// Returns the underlying `JSObject`.
    pub fn callback(&self) -> *mut JSObject {
        self.object.callback
    }
}

impl CallbackInterface {
    /// Create a new CallbackInterface object for the given `JSObject`.
    pub fn new(callback: *mut JSObject) -> CallbackInterface {
        CallbackInterface {
            object: CallbackObject {
                callback: callback
            }
        }
    }

    /// Returns the property with the given `name`, if it is a callable object,
    /// or `Err(())` otherwise. If it returns `Err(())`, a JSAPI exception is
    /// pending.
    pub fn GetCallableProperty(&self, cx: *mut JSContext, name: &str) -> Result<JSVal, ()> {
        let mut callable = UndefinedValue();
        unsafe {
            let name = name.to_c_str();
            if JS_GetProperty(cx, self.callback(), name.as_ptr(), &mut callable) == 0 {
                return Err(());
            }

            if !callable.is_object() ||
               JS_ObjectIsCallable(cx, callable.to_object()) == 0 {
                // FIXME(#347)
                //ThrowErrorMessage(cx, MSG_NOT_CALLABLE, description.get());
                return Err(());
            }
        }
        Ok(callable)
    }
}

/// Wraps the reflector for `p` into the compartment of `cx`.
pub fn WrapCallThisObject<T: Reflectable>(cx: *mut JSContext,
                                          p: JSRef<T>) -> *mut JSObject {
    let mut obj = p.reflector().get_jsobject();
    assert!(!obj.is_null());

    unsafe {
        if JS_WrapObject(cx, &mut obj) == 0 {
            return ptr::null_mut();
        }
    }

    return obj;
}

/// A class that performs whatever setup we need to safely make a call while
/// this class is on the stack. After `new` returns, the call is safe to make.
pub struct CallSetup {
    /// The `JSContext` used for the call.
    cx: *mut JSContext,
    /// The exception handling used for the call.
    handling: ExceptionHandling,
}

impl CallSetup {
    /// Performs the setup needed to make a call.
    #[allow(unrooted_must_root)]
    pub fn new<T: CallbackContainer>(callback: T, handling: ExceptionHandling) -> CallSetup {
        let global = global_object_for_js_object(callback.callback());
        let global = global.root();
        let cx = global.r().get_cx();

        CallSetup {
            cx: cx,
            handling: handling,
        }
    }

    /// Returns the `JSContext` used for the call.
    pub fn GetContext(&self) -> *mut JSContext {
        self.cx
    }
}

impl Drop for CallSetup {
    fn drop(&mut self) {
        let mut need_to_deal_with_exception = unsafe { JS_IsExceptionPending(self.cx) } != 0;
        if self.handling == ExceptionHandling::Rethrow && need_to_deal_with_exception {
            let mut exn = UndefinedValue();
            let got_exn = unsafe {
                JS_GetPendingException(self.cx, &mut exn) != 0
            };

            if got_exn {
                //TODO: actually rethrow instead of eagerly reporting.
                //      Gecko stores a mutable reference to an ErrorResult
                //      abstraction that can store a JS exception and
                //      report it at content boundaries. Our return value
                //      wrappers around Result<U,V> make that more difficult.
                unsafe {
                    JS_ReportPendingException(self.cx);
                }
                need_to_deal_with_exception = false;
            }
        }

        if need_to_deal_with_exception {
            // Either we're supposed to report our exceptions, or we're supposed to
            // re-throw them but we failed to JS_GetPendingException.  Either way,
            // just report the pending exception, if any.

            unsafe {
                let old_global = JS_GetGlobalObject(self.cx);
                with_compartment(self.cx, old_global, || {
                    JS_ReportPendingException(self.cx)
                });
            }
        }
    }
}
<commit_msg>Stop pretending to do anything except eagerly report pending exceptions after invoking a callback.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![deny(missing_docs)]

//! Base classes to work with IDL callbacks.

use dom::bindings::global::global_object_for_js_object;
use dom::bindings::js::JSRef;
use dom::bindings::utils::Reflectable;
use js::jsapi::{JSContext, JSObject, JS_WrapObject, JS_ObjectIsCallable, JS_GetGlobalObject};
use js::jsapi::{JS_GetProperty, JS_IsExceptionPending, JS_ReportPendingException};
use js::jsval::{JSVal, UndefinedValue};
use js::rust::with_compartment;

use std::ptr;

/// The exception handling used for a call.
#[deriving(Copy, PartialEq)]
pub enum ExceptionHandling {
    /// Report any exception and don't throw it to the caller code.
    Report,
    /// Throw any exception to the caller code.
    Rethrow
}

/// A common base class for representing IDL callback function types.
#[deriving(Copy, Clone,PartialEq)]
#[jstraceable]
pub struct CallbackFunction {
    object: CallbackObject
}

impl CallbackFunction {
    /// Create a new `CallbackFunction` for this object.
    pub fn new(callback: *mut JSObject) -> CallbackFunction {
        CallbackFunction {
            object: CallbackObject {
                callback: callback
            }
        }
    }
}

/// A common base class for representing IDL callback interface types.
#[deriving(Copy, Clone,PartialEq)]
#[jstraceable]
pub struct CallbackInterface {
    object: CallbackObject
}

/// A common base class for representing IDL callback function and
/// callback interface types.
#[allow(raw_pointer_deriving)]
#[deriving(Copy, Clone,PartialEq)]
#[jstraceable]
struct CallbackObject {
    /// The underlying `JSObject`.
    callback: *mut JSObject,
}

/// A trait to be implemented by concrete IDL callback function and
/// callback interface types.
pub trait CallbackContainer {
    /// Create a new CallbackContainer object for the given `JSObject`.
    fn new(callback: *mut JSObject) -> Self;
    /// Returns the underlying `JSObject`.
    fn callback(&self) -> *mut JSObject;
}

impl CallbackInterface {
    /// Returns the underlying `JSObject`.
    pub fn callback(&self) -> *mut JSObject {
        self.object.callback
    }
}

impl CallbackFunction {
    /// Returns the underlying `JSObject`.
    pub fn callback(&self) -> *mut JSObject {
        self.object.callback
    }
}

impl CallbackInterface {
    /// Create a new CallbackInterface object for the given `JSObject`.
    pub fn new(callback: *mut JSObject) -> CallbackInterface {
        CallbackInterface {
            object: CallbackObject {
                callback: callback
            }
        }
    }

    /// Returns the property with the given `name`, if it is a callable object,
    /// or `Err(())` otherwise. If it returns `Err(())`, a JSAPI exception is
    /// pending.
    pub fn GetCallableProperty(&self, cx: *mut JSContext, name: &str) -> Result<JSVal, ()> {
        let mut callable = UndefinedValue();
        unsafe {
            let name = name.to_c_str();
            if JS_GetProperty(cx, self.callback(), name.as_ptr(), &mut callable) == 0 {
                return Err(());
            }

            if !callable.is_object() ||
               JS_ObjectIsCallable(cx, callable.to_object()) == 0 {
                // FIXME(#347)
                //ThrowErrorMessage(cx, MSG_NOT_CALLABLE, description.get());
                return Err(());
            }
        }
        Ok(callable)
    }
}

/// Wraps the reflector for `p` into the compartment of `cx`.
pub fn WrapCallThisObject<T: Reflectable>(cx: *mut JSContext,
                                          p: JSRef<T>) -> *mut JSObject {
    let mut obj = p.reflector().get_jsobject();
    assert!(!obj.is_null());

    unsafe {
        if JS_WrapObject(cx, &mut obj) == 0 {
            return ptr::null_mut();
        }
    }

    return obj;
}

/// A class that performs whatever setup we need to safely make a call while
/// this class is on the stack. After `new` returns, the call is safe to make.
pub struct CallSetup {
    /// The `JSContext` used for the call.
    cx: *mut JSContext,
    /// The exception handling used for the call.
    _handling: ExceptionHandling,
}

impl CallSetup {
    /// Performs the setup needed to make a call.
    #[allow(unrooted_must_root)]
    pub fn new<T: CallbackContainer>(callback: T, handling: ExceptionHandling) -> CallSetup {
        let global = global_object_for_js_object(callback.callback());
        let global = global.root();
        let cx = global.r().get_cx();

        CallSetup {
            cx: cx,
            _handling: handling,
        }
    }

    /// Returns the `JSContext` used for the call.
    pub fn GetContext(&self) -> *mut JSContext {
        self.cx
    }
}

impl Drop for CallSetup {
    fn drop(&mut self) {
        let need_to_deal_with_exception = unsafe { JS_IsExceptionPending(self.cx) } != 0;
        if need_to_deal_with_exception {
            unsafe {
                let old_global = JS_GetGlobalObject(self.cx);
                with_compartment(self.cx, old_global, || {
                    JS_ReportPendingException(self.cx)
                });
            }
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::config::{Config, ProjectConfig};
use common::NamedItem;
use graphql_ir::{FragmentDefinition, OperationDefinition};
use graphql_transforms::{
    is_preloadable_operation, DATA_DRIVEN_DEPENDENCY_METADATA_KEY, INLINE_DATA_CONSTANTS,
};
use relay_codegen::{build_request_params, Printer};
use relay_typegen::generate_fragment_type;
use schema::Schema;
use signedsource::{sign_file, SIGNING_TOKEN};
use std::fmt::Write;

pub enum ArtifactContent<'a> {
    Operation {
        normalization_operation: &'a OperationDefinition,
        reader_operation: &'a OperationDefinition,
        typegen_operation: &'a OperationDefinition,
        source_hash: String,
        text: String,
        id_and_text_hash: Option<(String, String)>,
    },
    Fragment {
        reader_fragment: &'a FragmentDefinition,
        typegen_fragment: &'a FragmentDefinition,
        source_hash: String,
    },
    SplitOperation {
        normalization_operation: &'a OperationDefinition,
        source_hash: String,
    },
    Generic {
        content: Vec<u8>,
    },
}

impl<'a> ArtifactContent<'a> {
    pub fn as_bytes(
        &self,
        config: &Config,
        project_config: &ProjectConfig,
        printer: &mut Printer,
        schema: &Schema,
    ) -> Vec<u8> {
        match self {
            ArtifactContent::Operation {
                normalization_operation,
                reader_operation,
                typegen_operation,
                source_hash,
                text,
                id_and_text_hash,
            } => generate_operation(
                config,
                project_config,
                printer,
                schema,
                normalization_operation,
                reader_operation,
                typegen_operation,
                source_hash.into(),
                text,
                id_and_text_hash,
            ),
            ArtifactContent::SplitOperation {
                normalization_operation,
                source_hash,
            } => generate_split_operation(
                config,
                printer,
                schema,
                normalization_operation,
                source_hash,
            ),
            ArtifactContent::Fragment {
                reader_fragment,
                typegen_fragment,
                source_hash,
            } => generate_fragment(
                config,
                project_config,
                printer,
                schema,
                reader_fragment,
                typegen_fragment,
                source_hash,
            ),
            ArtifactContent::Generic { content } => content.clone(),
        }
    }
}

#[allow(clippy::too_many_arguments)]
fn generate_operation(
    config: &Config,
    project_config: &ProjectConfig,
    printer: &mut Printer,
    schema: &Schema,
    normalization_operation: &OperationDefinition,
    reader_operation: &OperationDefinition,
    typegen_operation: &OperationDefinition,
    source_hash: String,
    text: &str,
    id_and_text_hash: &Option<(String, String)>,
) -> Vec<u8> {
    let mut request_parameters = build_request_params(&normalization_operation);
    let operation_hash: Option<String> = if let Some((id, text_hash)) = id_and_text_hash {
        request_parameters.id = Some(id.clone());
        Some(text_hash.clone())
    } else {
        request_parameters.text = Some(text.into());
        None
    };
    let operation_fragment = FragmentDefinition {
        name: reader_operation.name,
        variable_definitions: reader_operation.variable_definitions.clone(),
        selections: reader_operation.selections.clone(),
        used_global_variables: Default::default(),
        directives: reader_operation.directives.clone(),
        type_condition: reader_operation.type_,
    };
    let mut content = get_content_start(config);
    writeln!(content, " * {}", SIGNING_TOKEN).unwrap();
    if let Some(operation_hash) = operation_hash {
        writeln!(content, " * @relayHash {}", operation_hash).unwrap();
    }
    writeln!(content, " * @flow").unwrap();
    writeln!(content, " * @lightSyntaxTransform").unwrap();
    writeln!(content, " * @nogrep").unwrap();
    if let Some(codegen_command) = &config.codegen_command {
        writeln!(content, " * @codegen-command: {}", codegen_command).unwrap();
    }
    writeln!(content, " */\n").unwrap();
    writeln!(content, "/* eslint-disable */\n").unwrap();
    writeln!(content, "'use strict';\n").unwrap();
    if let Some(id) = &request_parameters.id {
        writeln!(content, "// @relayRequestID {}\n", id).unwrap();
    }
    writeln!(
        content,
        "/*::\nimport type {{ ConcreteRequest }} from 'relay-runtime';\n{}*/\n",
        relay_typegen::generate_operation_type(
            typegen_operation,
            normalization_operation,
            schema,
            &project_config.typegen_config,
        )
    )
    .unwrap();
    writeln!(content, "/*\n{}*/\n", text).unwrap();
    writeln!(
        content,
        "var node/*: ConcreteRequest*/ = {};\n",
        printer.print_request_deduped(
            schema,
            normalization_operation,
            &operation_fragment,
            request_parameters,
        )
    )
    .unwrap();
    writeln!(content, "if (__DEV__) {{").unwrap();
    writeln!(content, "  (node/*: any*/).hash = \"{}\";", source_hash).unwrap();
    writeln!(content, "}}\n").unwrap();
    // TODO: T67052528 - revisit this, once we move fb-specific transforms under the feature flag
    if is_preloadable_operation(normalization_operation) {
        writeln!(
            content,
            "if (node.params.id != null) {{\n  require('relay-runtime').PreloadableQueryRegistry.set(node.params.id, node);\n}}\n",
        )
        .unwrap();
    }
    writeln!(content, "module.exports = node;").unwrap();
    sign_file(&content).into_bytes()
}

fn generate_split_operation(
    config: &Config,
    printer: &mut Printer,
    schema: &Schema,
    node: &OperationDefinition,
    source_hash: &str,
) -> Vec<u8> {
    let mut content = get_content_start(config);
    writeln!(content, " * {}", SIGNING_TOKEN).unwrap();
    writeln!(content, " * @flow").unwrap();
    writeln!(content, " * @lightSyntaxTransform").unwrap();
    writeln!(content, " * @nogrep").unwrap();
    if let Some(codegen_command) = &config.codegen_command {
        writeln!(content, " * @codegen-command: {}", codegen_command).unwrap();
    }
    writeln!(content, " */\n").unwrap();
    writeln!(content, "/* eslint-disable */\n").unwrap();
    writeln!(content, "'use strict';\n").unwrap();
    writeln!(
        content,
        "/*::\nimport type {{ NormalizationSplitOperation }} from 'relay-runtime';\n\n*/\n"
    )
    .unwrap();
    writeln!(
        content,
        "var node/*: NormalizationSplitOperation*/ = {};\n",
        printer.print_operation_deduped(schema, node)
    )
    .unwrap();
    writeln!(content, "if (__DEV__) {{").unwrap();
    writeln!(content, "  (node/*: any*/).hash = \"{}\";", source_hash).unwrap();
    writeln!(content, "}}\n").unwrap();
    writeln!(content, "module.exports = node;").unwrap();
    sign_file(&content).into_bytes()
}

fn generate_fragment(
    config: &Config,
    project_config: &ProjectConfig,
    printer: &mut Printer,
    schema: &Schema,
    reader_fragment: &FragmentDefinition,
    typegen_fragment: &FragmentDefinition,
    source_hash: &str,
) -> Vec<u8> {
    let mut content = get_content_start(config);
    writeln!(content, " * {}", SIGNING_TOKEN).unwrap();
    writeln!(content, " * @flow").unwrap();
    writeln!(content, " * @lightSyntaxTransform").unwrap();
    writeln!(content, " * @nogrep").unwrap();
    if let Some(codegen_command) = &config.codegen_command {
        writeln!(content, " * @codegen-command: {}", codegen_command).unwrap();
    }
    writeln!(content, " */\n").unwrap();
    writeln!(content, "/* eslint-disable */\n").unwrap();
    writeln!(content, "'use strict';\n").unwrap();
    let relay_3d_metadata = reader_fragment
        .directives
        .named(*DATA_DRIVEN_DEPENDENCY_METADATA_KEY);
    if let Some(relay_3d_metadata) = relay_3d_metadata {
        for arg in &relay_3d_metadata.arguments {
            let value = match arg.value.item {
                graphql_ir::Value::Constant(graphql_ir::ConstantValue::String(value)) => value,
                _ => panic!("Unexpected value for Relay 3d argument"),
            };
            writeln!(
                content,
                "// @dataDrivenDependency {} {}\n",
                arg.name.item, value
            )
            .unwrap();
        }
    }

    let reader_node_flow_type = if reader_fragment
        .directives
        .named(INLINE_DATA_CONSTANTS.directive_name)
        .is_some()
    {
        "ReaderInlineDataFragment"
    } else {
        "ReaderFragment"
    };
    writeln!(
        content,
        "/*::\nimport type {{ {} }} from 'relay-runtime';\n{}*/\n",
        reader_node_flow_type,
        generate_fragment_type(typegen_fragment, schema, &project_config.typegen_config)
    )
    .unwrap();
    writeln!(
        content,
        "var node/*: {}*/ = {};\n",
        reader_node_flow_type,
        printer.print_fragment_deduped(schema, reader_fragment)
    )
    .unwrap();
    writeln!(content, "if (__DEV__) {{").unwrap();
    writeln!(content, "  (node/*: any*/).hash = \"{}\";", source_hash).unwrap();
    writeln!(content, "}}\n").unwrap();
    writeln!(content, "module.exports = node;").unwrap();
    sign_file(&content).into_bytes()
}

fn get_content_start(config: &Config) -> String {
    let mut content = String::new();
    writeln!(content, "/**").unwrap();
    if !config.header.is_empty() {
        for header_line in &config.header {
            writeln!(content, " * {}", header_line).unwrap();
        }
        writeln!(content, " *").unwrap();
    }
    content
}
<commit_msg>fix printing of multiple @dataDrivenDependency annotations<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::config::{Config, ProjectConfig};
use common::NamedItem;
use graphql_ir::{FragmentDefinition, OperationDefinition};
use graphql_transforms::{
    is_preloadable_operation, DATA_DRIVEN_DEPENDENCY_METADATA_KEY, INLINE_DATA_CONSTANTS,
};
use relay_codegen::{build_request_params, Printer};
use relay_typegen::generate_fragment_type;
use schema::Schema;
use signedsource::{sign_file, SIGNING_TOKEN};
use std::fmt::Write;

pub enum ArtifactContent<'a> {
    Operation {
        normalization_operation: &'a OperationDefinition,
        reader_operation: &'a OperationDefinition,
        typegen_operation: &'a OperationDefinition,
        source_hash: String,
        text: String,
        id_and_text_hash: Option<(String, String)>,
    },
    Fragment {
        reader_fragment: &'a FragmentDefinition,
        typegen_fragment: &'a FragmentDefinition,
        source_hash: String,
    },
    SplitOperation {
        normalization_operation: &'a OperationDefinition,
        source_hash: String,
    },
    Generic {
        content: Vec<u8>,
    },
}

impl<'a> ArtifactContent<'a> {
    pub fn as_bytes(
        &self,
        config: &Config,
        project_config: &ProjectConfig,
        printer: &mut Printer,
        schema: &Schema,
    ) -> Vec<u8> {
        match self {
            ArtifactContent::Operation {
                normalization_operation,
                reader_operation,
                typegen_operation,
                source_hash,
                text,
                id_and_text_hash,
            } => generate_operation(
                config,
                project_config,
                printer,
                schema,
                normalization_operation,
                reader_operation,
                typegen_operation,
                source_hash.into(),
                text,
                id_and_text_hash,
            ),
            ArtifactContent::SplitOperation {
                normalization_operation,
                source_hash,
            } => generate_split_operation(
                config,
                printer,
                schema,
                normalization_operation,
                source_hash,
            ),
            ArtifactContent::Fragment {
                reader_fragment,
                typegen_fragment,
                source_hash,
            } => generate_fragment(
                config,
                project_config,
                printer,
                schema,
                reader_fragment,
                typegen_fragment,
                source_hash,
            ),
            ArtifactContent::Generic { content } => content.clone(),
        }
    }
}

#[allow(clippy::too_many_arguments)]
fn generate_operation(
    config: &Config,
    project_config: &ProjectConfig,
    printer: &mut Printer,
    schema: &Schema,
    normalization_operation: &OperationDefinition,
    reader_operation: &OperationDefinition,
    typegen_operation: &OperationDefinition,
    source_hash: String,
    text: &str,
    id_and_text_hash: &Option<(String, String)>,
) -> Vec<u8> {
    let mut request_parameters = build_request_params(&normalization_operation);
    let operation_hash: Option<String> = if let Some((id, text_hash)) = id_and_text_hash {
        request_parameters.id = Some(id.clone());
        Some(text_hash.clone())
    } else {
        request_parameters.text = Some(text.into());
        None
    };
    let operation_fragment = FragmentDefinition {
        name: reader_operation.name,
        variable_definitions: reader_operation.variable_definitions.clone(),
        selections: reader_operation.selections.clone(),
        used_global_variables: Default::default(),
        directives: reader_operation.directives.clone(),
        type_condition: reader_operation.type_,
    };
    let mut content = get_content_start(config);
    writeln!(content, " * {}", SIGNING_TOKEN).unwrap();
    if let Some(operation_hash) = operation_hash {
        writeln!(content, " * @relayHash {}", operation_hash).unwrap();
    }
    writeln!(content, " * @flow").unwrap();
    writeln!(content, " * @lightSyntaxTransform").unwrap();
    writeln!(content, " * @nogrep").unwrap();
    if let Some(codegen_command) = &config.codegen_command {
        writeln!(content, " * @codegen-command: {}", codegen_command).unwrap();
    }
    writeln!(content, " */\n").unwrap();
    writeln!(content, "/* eslint-disable */\n").unwrap();
    writeln!(content, "'use strict';\n").unwrap();
    if let Some(id) = &request_parameters.id {
        writeln!(content, "// @relayRequestID {}\n", id).unwrap();
    }
    writeln!(
        content,
        "/*::\nimport type {{ ConcreteRequest }} from 'relay-runtime';\n{}*/\n",
        relay_typegen::generate_operation_type(
            typegen_operation,
            normalization_operation,
            schema,
            &project_config.typegen_config,
        )
    )
    .unwrap();
    writeln!(content, "/*\n{}*/\n", text).unwrap();
    writeln!(
        content,
        "var node/*: ConcreteRequest*/ = {};\n",
        printer.print_request_deduped(
            schema,
            normalization_operation,
            &operation_fragment,
            request_parameters,
        )
    )
    .unwrap();
    writeln!(content, "if (__DEV__) {{").unwrap();
    writeln!(content, "  (node/*: any*/).hash = \"{}\";", source_hash).unwrap();
    writeln!(content, "}}\n").unwrap();
    // TODO: T67052528 - revisit this, once we move fb-specific transforms under the feature flag
    if is_preloadable_operation(normalization_operation) {
        writeln!(
            content,
            "if (node.params.id != null) {{\n  require('relay-runtime').PreloadableQueryRegistry.set(node.params.id, node);\n}}\n",
        )
        .unwrap();
    }
    writeln!(content, "module.exports = node;").unwrap();
    sign_file(&content).into_bytes()
}

fn generate_split_operation(
    config: &Config,
    printer: &mut Printer,
    schema: &Schema,
    node: &OperationDefinition,
    source_hash: &str,
) -> Vec<u8> {
    let mut content = get_content_start(config);
    writeln!(content, " * {}", SIGNING_TOKEN).unwrap();
    writeln!(content, " * @flow").unwrap();
    writeln!(content, " * @lightSyntaxTransform").unwrap();
    writeln!(content, " * @nogrep").unwrap();
    if let Some(codegen_command) = &config.codegen_command {
        writeln!(content, " * @codegen-command: {}", codegen_command).unwrap();
    }
    writeln!(content, " */\n").unwrap();
    writeln!(content, "/* eslint-disable */\n").unwrap();
    writeln!(content, "'use strict';\n").unwrap();
    writeln!(
        content,
        "/*::\nimport type {{ NormalizationSplitOperation }} from 'relay-runtime';\n\n*/\n"
    )
    .unwrap();
    writeln!(
        content,
        "var node/*: NormalizationSplitOperation*/ = {};\n",
        printer.print_operation_deduped(schema, node)
    )
    .unwrap();
    writeln!(content, "if (__DEV__) {{").unwrap();
    writeln!(content, "  (node/*: any*/).hash = \"{}\";", source_hash).unwrap();
    writeln!(content, "}}\n").unwrap();
    writeln!(content, "module.exports = node;").unwrap();
    sign_file(&content).into_bytes()
}

fn generate_fragment(
    config: &Config,
    project_config: &ProjectConfig,
    printer: &mut Printer,
    schema: &Schema,
    reader_fragment: &FragmentDefinition,
    typegen_fragment: &FragmentDefinition,
    source_hash: &str,
) -> Vec<u8> {
    let mut content = get_content_start(config);
    writeln!(content, " * {}", SIGNING_TOKEN).unwrap();
    writeln!(content, " * @flow").unwrap();
    writeln!(content, " * @lightSyntaxTransform").unwrap();
    writeln!(content, " * @nogrep").unwrap();
    if let Some(codegen_command) = &config.codegen_command {
        writeln!(content, " * @codegen-command: {}", codegen_command).unwrap();
    }
    writeln!(content, " */\n").unwrap();
    writeln!(content, "/* eslint-disable */\n").unwrap();
    writeln!(content, "'use strict';\n").unwrap();
    let relay_3d_metadata = reader_fragment
        .directives
        .named(*DATA_DRIVEN_DEPENDENCY_METADATA_KEY);
    if let Some(relay_3d_metadata) = relay_3d_metadata {
        for arg in &relay_3d_metadata.arguments {
            let value = match arg.value.item {
                graphql_ir::Value::Constant(graphql_ir::ConstantValue::String(value)) => value,
                _ => panic!("Unexpected value for Relay 3d argument"),
            };
            writeln!(
                content,
                "// @dataDrivenDependency {} {}",
                arg.name.item, value
            )
            .unwrap();
        }
        writeln!(content).unwrap();
    }

    let reader_node_flow_type = if reader_fragment
        .directives
        .named(INLINE_DATA_CONSTANTS.directive_name)
        .is_some()
    {
        "ReaderInlineDataFragment"
    } else {
        "ReaderFragment"
    };
    writeln!(
        content,
        "/*::\nimport type {{ {} }} from 'relay-runtime';\n{}*/\n",
        reader_node_flow_type,
        generate_fragment_type(typegen_fragment, schema, &project_config.typegen_config)
    )
    .unwrap();
    writeln!(
        content,
        "var node/*: {}*/ = {};\n",
        reader_node_flow_type,
        printer.print_fragment_deduped(schema, reader_fragment)
    )
    .unwrap();
    writeln!(content, "if (__DEV__) {{").unwrap();
    writeln!(content, "  (node/*: any*/).hash = \"{}\";", source_hash).unwrap();
    writeln!(content, "}}\n").unwrap();
    writeln!(content, "module.exports = node;").unwrap();
    sign_file(&content).into_bytes()
}

fn get_content_start(config: &Config) -> String {
    let mut content = String::new();
    writeln!(content, "/**").unwrap();
    if !config.header.is_empty() {
        for header_line in &config.header {
            writeln!(content, " * {}", header_line).unwrap();
        }
        writeln!(content, " *").unwrap();
    }
    content
}
<|endoftext|>