Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into swernli/impl-attrs
Browse files Browse the repository at this point in the history
  • Loading branch information
swernli committed Oct 17, 2023
2 parents 7eaa894 + 0529438 commit 092a967
Show file tree
Hide file tree
Showing 30 changed files with 917 additions and 200 deletions.
5 changes: 1 addition & 4 deletions compiler/qsc/src/bin/qsc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,7 @@ fn main() -> miette::Result<ExitCode> {
Ok(ExitCode::SUCCESS)
} else {
for error in errors {
eprintln!(
"{:?}",
Report::new(WithSource::from_map(&unit.sources, error))
);
eprintln!("{:?}", Report::new(error));
}

Ok(ExitCode::FAILURE)
Expand Down
8 changes: 5 additions & 3 deletions compiler/qsc/src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ use qsc_hir::hir::PackageId;
use qsc_passes::{run_core_passes, run_default_passes, PackageType};
use thiserror::Error;

pub type Error = WithSource<ErrorKind>;

#[derive(Clone, Debug, Diagnostic, Error)]
#[diagnostic(transparent)]
#[error(transparent)]
pub enum Error {
pub enum ErrorKind {
Frontend(#[from] qsc_frontend::compile::Error),
Pass(#[from] qsc_passes::Error),
}
Expand All @@ -29,12 +31,12 @@ pub fn compile(
let mut unit = qsc_frontend::compile::compile(store, dependencies, sources, target);
let mut errors = Vec::new();
for error in unit.errors.drain(..) {
errors.push(error.into());
errors.push(WithSource::from_map(&unit.sources, error.into()));
}

if errors.is_empty() {
for error in run_default_passes(store.core(), &mut unit, package_type, target) {
errors.push(error.into());
errors.push(WithSource::from_map(&unit.sources, error.into()));
}
}

Expand Down
24 changes: 12 additions & 12 deletions compiler/qsc/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,33 @@
// Licensed under the MIT License.

use miette::Diagnostic;
use qsc_frontend::{compile::PackageStore, error::WithSource};
use std::{
error::Error,
fmt::{self, Debug, Display, Formatter},
};
use qsc_frontend::compile::PackageStore;
use std::fmt::{self, Debug, Display, Formatter};
use thiserror::Error;

pub use qsc_frontend::error::WithSource;

#[derive(Clone, Debug, Error)]
pub struct WithStack<E>
where
E: Diagnostic + Error,
{
pub struct WithStack<E> {
error: E,
stack_trace: Option<String>,
}

impl<E: Diagnostic> WithStack<E> {
impl<E> WithStack<E> {
pub(super) fn new(error: E, stack_trace: Option<String>) -> Self {
WithStack { error, stack_trace }
}

pub(super) fn stack_trace(&self) -> &Option<String> {
&self.stack_trace
}

pub fn error(&self) -> &E {
&self.error
}
}

impl<E: Display + Diagnostic> Display for WithStack<E> {
impl<E: Display> Display for WithStack<E> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
std::fmt::Display::fmt(&self.error, f)
}
Expand Down Expand Up @@ -69,7 +69,7 @@ impl<E: Diagnostic> Diagnostic for WithStack<E> {
}
}

pub fn from_eval(
pub(super) fn from_eval(
error: qsc_eval::Error,
store: &PackageStore,
stack_trace: Option<String>,
Expand Down
10 changes: 5 additions & 5 deletions compiler/qsc/src/incremental.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ pub struct Compiler {
}

/// An incremental compiler error.
pub type Errors = Vec<WithSource<compile::Error>>;
pub type Errors = Vec<compile::Error>;

impl Compiler {
/// Creates a new incremental compiler, compiling the passed in sources.
Expand All @@ -49,7 +49,7 @@ impl Compiler {

let (unit, errors) = compile(&store, &dependencies, sources, package_type, target);
if !errors.is_empty() {
return Err(into_errors_with_source(errors, &unit.sources));
return Err(errors);
}

let source_package_id = store.insert(unit);
Expand Down Expand Up @@ -171,7 +171,7 @@ impl Compiler {

fn into_errors_with_source<T>(errors: Vec<T>, sources: &SourceMap) -> Errors
where
compile::Error: From<T>,
compile::ErrorKind: From<T>,
{
errors
.into_iter()
Expand All @@ -181,8 +181,8 @@ where

fn into_errors<T>(errors: Vec<WithSource<T>>) -> Errors
where
compile::Error: From<T>,
T: Diagnostic,
compile::ErrorKind: From<T>,
T: Diagnostic + Send + Sync,
{
errors
.into_iter()
Expand Down
4 changes: 2 additions & 2 deletions compiler/qsc/src/interpret/stateful.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ impl Error {
pub enum Error {
#[error(transparent)]
#[diagnostic(transparent)]
Compile(#[from] WithSource<crate::compile::Error>),
Compile(#[from] crate::compile::Error),
#[error(transparent)]
#[diagnostic(transparent)]
Pass(#[from] WithSource<qsc_passes::Error>),
Expand Down Expand Up @@ -663,7 +663,7 @@ fn eval_error(
vec![error::from_eval(error, package_store, stack_trace).into()]
}

fn into_errors(errors: Vec<WithSource<crate::compile::Error>>) -> Vec<Error> {
fn into_errors(errors: Vec<crate::compile::Error>) -> Vec<Error> {
errors
.into_iter()
.map(|error| Error::Compile(error.into_with_source()))
Expand Down
2 changes: 1 addition & 1 deletion compiler/qsc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#![allow(clippy::missing_errors_doc, clippy::missing_panics_doc)]

pub mod compile;
mod error;
pub mod error;
pub mod incremental;
pub mod interpret;

Expand Down
28 changes: 17 additions & 11 deletions compiler/qsc_frontend/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,15 @@ pub struct WithSource<E> {
error: E,
}

impl<E: Diagnostic> WithSource<E> {
impl<E: Diagnostic + Send + Sync> WithSource<E> {
pub fn error(&self) -> &E {
&self.error
}

pub fn into_error(self) -> E {
self.error
}
}

impl<E: Diagnostic> WithSource<E> {
/// Construct a diagnostic with source information from a source map.
/// Since errors may contain labeled spans from any source file in the
/// compilation, the entire source map is needed to resolve offsets.
Expand Down Expand Up @@ -68,6 +66,20 @@ impl<E: Diagnostic> WithSource<E> {
error: self.error.into(),
}
}

/// Takes a span that uses `SourceMap` offsets, and returns
/// a span that is relative to the `Source` that the span falls into,
/// along with a reference to the `Source`.
pub fn resolve_span(&self, span: &SourceSpan) -> (&Source, SourceSpan) {
let offset = u32::try_from(span.offset()).expect("expected the offset to fit into u32");
let source = self
.sources
.iter()
.rev()
.find(|source| offset >= source.offset)
.expect("expected to find source at span");
(source, with_offset(span, |o| o - (source.offset as usize)))
}
}

impl<E: Diagnostic> Error for WithSource<E> {
Expand Down Expand Up @@ -123,16 +135,10 @@ impl<E: Diagnostic + Sync + Send> SourceCode for WithSource<E> {
context_lines_before: usize,
context_lines_after: usize,
) -> Result<Box<dyn SpanContents<'a> + 'a>, MietteError> {
let offset = u32::try_from(span.offset()).expect("expected the offset to fit into u32");
let source = self
.sources
.iter()
.rev()
.find(|source| offset >= source.offset)
.expect("expected to find source at span");
let (source, source_relative_span) = self.resolve_span(span);

let contents = source.contents.read_span(
&with_offset(span, |o| o - (source.offset as usize)),
&source_relative_span,
context_lines_before,
context_lines_after,
)?;
Expand Down
46 changes: 46 additions & 0 deletions compiler/qsc_frontend/src/error/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,52 @@ fn error_spans_eof() {
.assert_eq(&formatted_error);
}

#[test]
fn resolve_spans() {
let test1_contents = "namespace Foo {}";
let test2_contents = "namespace Bar {}";
let mut sources = SourceMap::default();
let test1_offset = sources.push("test1.qs".into(), test1_contents.into());
let test2_offset = sources.push("test2.qs".into(), test2_contents.into());

let error = TestError::TwoSpans(
"value".into(),
span_with_offset(test1_offset, 10, 13),
span_with_offset(test2_offset, 10, 13),
);

let with_source = WithSource::from_map(&sources, error);

let resolved_spans = with_source
.labels()
.expect("expected labels to exist")
.map(|l| {
let resolved = with_source.resolve_span(l.inner());
(
resolved.0.name.to_string(),
resolved.1.offset(),
resolved.1.len(),
)
})
.collect::<Vec<_>>();

expect![[r#"
[
(
"test1.qs",
10,
3,
),
(
"test2.qs",
10,
3,
),
]
"#]]
.assert_debug_eq(&resolved_spans);
}

fn span_with_offset(offset: u32, lo: u32, hi: u32) -> Span {
Span {
lo: lo + offset,
Expand Down
9 changes: 5 additions & 4 deletions compiler/qsc_frontend/src/typeck/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -331,16 +331,17 @@ impl<'a> Context<'a> {
let prev_ret_ty = self.return_ty.take();
let output_ty = self.inferrer.fresh_ty(TySource::not_divergent(body.span));
self.return_ty = Some(output_ty);
let body_ty = self.infer_expr(body).ty;
let body_partial = self.infer_expr(body);
let output_ty = self
.return_ty
.take()
.expect("return type should be present");
self.return_ty = prev_ret_ty;
if body_ty != Ty::UNIT {
// Only when the type of the body is not `UNIT` do we need to unify with the inferred output type.
if !body_partial.diverges {
// Only when the type of the body converges do we need to unify with the inferred output type.
// Otherwise we'd get spurious errors from lambdas that use explicit return-expr rather than implicit.
self.inferrer.eq(body.span, output_ty.clone(), body_ty);
self.inferrer
.eq(body.span, output_ty.clone(), body_partial.ty);
}
converge(Ty::Arrow(Box::new(Arrow {
kind: convert::callable_kind_from_ast(*kind),
Expand Down
Loading

0 comments on commit 092a967

Please sign in to comment.