use rustc_ast::Mutability;
use rustc_hir::lang_items::LangItem;
use rustc_middle::mir::TerminatorKind;
use rustc_middle::ty::layout::LayoutOf;
use rustc_span::{Span, Symbol};

use crate::interpret::{
    intrinsics::{InterpCx, Machine},
    MPlaceTy, MemoryKind, Scalar,
};

impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
    /// Walks up the callstack from the intrinsic's callsite, searching for the first callsite in a
    /// frame which is not `#[track_caller]`.
    pub(crate) fn find_closest_untracked_caller_location(&self) -> Span {
        for frame in self.stack().iter().rev() {
            debug!("find_closest_untracked_caller_location: checking frame {:?}", frame.instance);

            // Assert that the frame we look at is actually executing code currently
            // (`loc` is `Right` when we are unwinding and the frame does not require cleanup).
            let loc = frame.loc.left().unwrap();

            // This could be a non-`Call` terminator (such as `Drop`), or not a terminator at all
            // (such as `box`). Use the normal span by default.
            let mut source_info = *frame.body.source_info(loc);

            // If this is a `Call` terminator, use the `fn_span` instead.
            let block = &frame.body.basic_blocks[loc.block];
            if loc.statement_index == block.statements.len() {
                debug!(
                    "find_closest_untracked_caller_location: got terminator {:?} ({:?})",
                    block.terminator(),
                    block.terminator().kind
                );
                if let TerminatorKind::Call { fn_span, .. } = block.terminator().kind {
                    source_info.span = fn_span;
                }
            }

            // Walk up the `SourceScope`s, in case some of them are from MIR inlining.
            // If so, the starting `source_info.span` is in the innermost inlined
            // function, and will be replaced with outer callsite spans as long
            // as the inlined functions were `#[track_caller]`.
            loop {
                let scope_data = &frame.body.source_scopes[source_info.scope];

                if let Some((callee, callsite_span)) = scope_data.inlined {
                    // Stop inside the most nested non-`#[track_caller]` function,
                    // before ever reaching its caller (which is irrelevant).
                    if !callee.def.requires_caller_location(*self.tcx) {
                        return source_info.span;
                    }
                    source_info.span = callsite_span;
                }

                // Skip past all of the parents with `inlined: None`.
                match scope_data.inlined_parent_scope {
                    Some(parent) => source_info.scope = parent,
                    None => break,
                }
            }

            // Stop inside the most nested non-`#[track_caller]` function,
            // before ever reaching its caller (which is irrelevant).
            if !frame.instance.def.requires_caller_location(*self.tcx) {
                return source_info.span;
            }
        }

        span_bug!(self.cur_span(), "no non-`#[track_caller]` frame found")
    }

    /// Allocate a `const core::panic::Location` with the provided filename and line/column numbers.
    pub(crate) fn alloc_caller_location(
        &mut self,
        filename: Symbol,
        line: u32,
        col: u32,
    ) -> MPlaceTy<'tcx, M::Provenance> {
        let loc_details = &self.tcx.sess.opts.unstable_opts.location_detail;
        // This can fail if rustc runs out of memory right here. Trying to emit an error would be
        // pointless, since that would require allocating more memory than these short strings.
        let file = if loc_details.file {
            self.allocate_str(filename.as_str(), MemoryKind::CallerLocation, Mutability::Not)
                .unwrap()
        } else {
            // FIXME: This creates a new allocation each time. It might be preferable to
            // perform this allocation only once, and re-use the `MPlaceTy`.
            // See https://github.com/rust-lang/rust/pull/89920#discussion_r730012398
            self.allocate_str("<redacted>", MemoryKind::CallerLocation, Mutability::Not).unwrap()
        };
        let line = if loc_details.line { Scalar::from_u32(line) } else { Scalar::from_u32(0) };
        let col = if loc_details.column { Scalar::from_u32(col) } else { Scalar::from_u32(0) };

        // Allocate memory for `CallerLocation` struct.
        let loc_ty = self
            .tcx
            .type_of(self.tcx.require_lang_item(LangItem::PanicLocation, None))
            .subst(*self.tcx, self.tcx.mk_substs(&[self.tcx.lifetimes.re_erased.into()]));
        let loc_layout = self.layout_of(loc_ty).unwrap();
        let location = self.allocate(loc_layout, MemoryKind::CallerLocation).unwrap();

        // Initialize fields.
        self.write_immediate(file.to_ref(self), &self.mplace_field(&location, 0).unwrap().into())
            .expect("writing to memory we just allocated cannot fail");
        self.write_scalar(line, &self.mplace_field(&location, 1).unwrap().into())
            .expect("writing to memory we just allocated cannot fail");
        self.write_scalar(col, &self.mplace_field(&location, 2).unwrap().into())
            .expect("writing to memory we just allocated cannot fail");

        location
    }

    pub(crate) fn location_triple_for_span(&self, mut span: Span) -> (Symbol, u32, u32) {
        // Remove `Inlined` marks as they pollute `expansion_cause`.
        while span.is_inlined() {
            span.remove_mark();
        }
        let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
        let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo());
        (
            Symbol::intern(&caller.file.name.prefer_remapped().to_string_lossy()),
            u32::try_from(caller.line).unwrap(),
            u32::try_from(caller.col_display).unwrap().checked_add(1).unwrap(),
        )
    }

    pub fn alloc_caller_location_for_span(&mut self, span: Span) -> MPlaceTy<'tcx, M::Provenance> {
        let (file, line, column) = self.location_triple_for_span(span);
        self.alloc_caller_location(file, line, column)
    }
}
