Merge branch 'main' into inline-imports

This commit is contained in:
Agus Zubiaga 2024-04-20 12:01:11 -03:00
commit d5a38a26db
No known key found for this signature in database
667 changed files with 22300 additions and 14562 deletions

View file

@ -18,10 +18,22 @@ pub struct ModuleDocumentation {
pub exposed_symbols: VecSet<Symbol>,
}
impl ModuleDocumentation {
pub fn get_doc_for_symbol(&self, symbol_to_match: &Symbol) -> Option<String> {
self.entries.iter().find_map(|doc| match doc {
DocEntry::DocDef(DocDef { symbol, docs, .. }) if symbol == symbol_to_match => {
docs.clone()
}
_ => None,
})
}
}
#[derive(Debug, Clone)]
pub enum DocEntry {
DocDef(DocDef),
DetachedDoc(String),
ModuleDoc(String),
}
#[derive(Debug, Clone)]
@ -174,10 +186,10 @@ fn generate_entry_docs(
) -> Vec<DocEntry> {
use roc_parse::ast::Pattern;
let mut acc = Vec::with_capacity(defs.tags.len() + 1);
let mut doc_entries = Vec::with_capacity(defs.tags.len() + 1);
if let Some(docs) = comments_or_new_lines_to_docs(header_comments) {
acc.push(DetachedDoc(docs));
doc_entries.push(DocEntry::ModuleDoc(docs));
}
let mut before_comments_or_new_lines: Option<&[CommentOrNewline]> = None;
@ -200,7 +212,11 @@ fn generate_entry_docs(
match either_index.split() {
Err(value_index) => match &defs.value_defs[value_index.index()] {
ValueDef::Annotation(loc_pattern, loc_ann) => {
if let Pattern::Identifier(identifier) = loc_pattern.value {
if let Pattern::Identifier {
ident: identifier,
suffixed: _,
} = loc_pattern.value
{
// Check if this module exposes the def
if let Some(ident_id) = ident_ids.get_id(identifier) {
let name = identifier.to_string();
@ -211,7 +227,7 @@ fn generate_entry_docs(
type_vars: Vec::new(),
docs,
};
acc.push(DocEntry::DocDef(doc_def));
doc_entries.push(DocEntry::DocDef(doc_def));
}
}
}
@ -221,7 +237,11 @@ fn generate_entry_docs(
ann_type,
..
} => {
if let Pattern::Identifier(identifier) = ann_pattern.value {
if let Pattern::Identifier {
ident: identifier,
suffixed: _,
} = ann_pattern.value
{
// Check if this module exposes the def
if let Some(ident_id) = ident_ids.get_id(identifier) {
let doc_def = DocDef {
@ -231,13 +251,29 @@ fn generate_entry_docs(
symbol: Symbol::new(home, ident_id),
docs,
};
acc.push(DocEntry::DocDef(doc_def));
doc_entries.push(DocEntry::DocDef(doc_def));
}
}
}
ValueDef::Body(_, _) => {
// TODO generate docs for un-annotated bodies
ValueDef::Body(pattern, _) => {
if let Pattern::Identifier {
ident: identifier,
suffixed: _,
} = pattern.value
{
// Check if this module exposes the def
if let Some(ident_id) = ident_ids.get_id(identifier) {
let doc_def = DocDef {
name: identifier.to_string(),
type_annotation: TypeAnnotation::NoTypeAnn,
type_vars: Vec::new(),
symbol: Symbol::new(home, ident_id),
docs,
};
doc_entries.push(DocEntry::DocDef(doc_def));
}
}
}
ValueDef::Dbg { .. } => {
@ -257,7 +293,27 @@ fn generate_entry_docs(
ValueDef::IngestedFileImport { .. } => {
// Don't generate docs for ingested file imports
}
ValueDef::Stmt(loc_expr) => {
if let roc_parse::ast::Expr::Var {
ident: identifier, ..
} = loc_expr.value
{
// Check if this module exposes the def
if let Some(ident_id) = ident_ids.get_id(identifier) {
let doc_def = DocDef {
name: identifier.to_string(),
type_annotation: TypeAnnotation::NoTypeAnn,
type_vars: Vec::new(),
symbol: Symbol::new(home, ident_id),
docs,
};
doc_entries.push(DocEntry::DocDef(doc_def));
}
}
}
},
Ok(type_index) => match &defs.type_defs[type_index.index()] {
TypeDef::Alias {
header: TypeHeader { name, vars },
@ -266,7 +322,11 @@ fn generate_entry_docs(
let mut type_vars = Vec::new();
for var in vars.iter() {
if let Pattern::Identifier(ident_name) = var.value {
if let Pattern::Identifier {
ident: ident_name,
suffixed: _,
} = var.value
{
type_vars.push(ident_name.to_string());
}
}
@ -290,7 +350,7 @@ fn generate_entry_docs(
docs,
symbol: Symbol::new(home, ident_id),
};
acc.push(DocEntry::DocDef(doc_def));
doc_entries.push(DocEntry::DocDef(doc_def));
}
TypeDef::Opaque {
@ -300,7 +360,11 @@ fn generate_entry_docs(
let mut type_vars = Vec::new();
for var in vars.iter() {
if let Pattern::Identifier(ident_name) = var.value {
if let Pattern::Identifier {
ident: ident_name,
suffixed: _,
} = var.value
{
type_vars.push(ident_name.to_string());
}
}
@ -313,7 +377,7 @@ fn generate_entry_docs(
docs,
symbol: Symbol::new(home, ident_id),
};
acc.push(DocEntry::DocDef(doc_def));
doc_entries.push(DocEntry::DocDef(doc_def));
}
TypeDef::Ability {
@ -324,7 +388,11 @@ fn generate_entry_docs(
let mut type_vars = Vec::new();
for var in vars.iter() {
if let Pattern::Identifier(ident_name) = var.value {
if let Pattern::Identifier {
ident: ident_name,
suffixed: _,
} = var.value
{
type_vars.push(ident_name.to_string());
}
}
@ -353,7 +421,7 @@ fn generate_entry_docs(
type_vars,
docs,
};
acc.push(DocEntry::DocDef(doc_def));
doc_entries.push(DocEntry::DocDef(doc_def));
}
},
}
@ -365,40 +433,49 @@ fn generate_entry_docs(
let it = before_comments_or_new_lines.iter().flat_map(|e| e.iter());
for detached_doc in detached_docs_from_comments_and_new_lines(it) {
acc.push(DetachedDoc(detached_doc));
doc_entries.push(DetachedDoc(detached_doc));
}
acc
doc_entries
}
/// Does this type contain any types which are not exposed outside the package?
/// (If so, we shouldn't try to render a type annotation for it.)
fn contains_unexposed_type(
ann: &ast::TypeAnnotation,
type_ann: &ast::TypeAnnotation,
exposed_module_ids: &[ModuleId],
module_ids: &ModuleIds,
) -> bool {
use ast::TypeAnnotation::*;
match ann {
match type_ann {
// Apply is the one case that can directly return true.
Apply(module_name, _ident, loc_args) => {
let apply_module_id = module_ids.get_id(&(*module_name).into());
let loc_args_contains_unexposed_type = loc_args.iter().any(|loc_arg| {
contains_unexposed_type(&loc_arg.value, exposed_module_ids, module_ids)
});
// If the *ident* was unexposed, we would have gotten a naming error
// during canonicalization, so all we need to check is the module.
let module_id = module_ids.get_id(&(*module_name).into()).unwrap();
if let Some(module_id) = apply_module_id {
!exposed_module_ids.contains(&module_id) || loc_args_contains_unexposed_type
} else {
true
}
}
!exposed_module_ids.contains(&module_id)
|| loc_args.iter().any(|loc_arg| {
contains_unexposed_type(&loc_arg.value, exposed_module_ids, module_ids)
})
}
Malformed(_) | Inferred | Wildcard | BoundVariable(_) => false,
Function(loc_args, loc_ret) => {
let loc_args_contains_unexposed_type = loc_args.iter().any(|loc_arg| {
contains_unexposed_type(&loc_arg.value, exposed_module_ids, module_ids)
});
contains_unexposed_type(&loc_ret.value, exposed_module_ids, module_ids)
|| loc_args.iter().any(|loc_arg| {
contains_unexposed_type(&loc_arg.value, exposed_module_ids, module_ids)
})
|| loc_args_contains_unexposed_type
}
Record { fields, ext } => {
if let Some(loc_ext) = ext {
if contains_unexposed_type(&loc_ext.value, exposed_module_ids, module_ids) {
@ -428,6 +505,7 @@ fn contains_unexposed_type(
false
}
Tuple { elems: fields, ext } => {
if let Some(loc_ext) = ext {
if contains_unexposed_type(&loc_ext.value, exposed_module_ids, module_ids) {
@ -439,6 +517,7 @@ fn contains_unexposed_type(
contains_unexposed_type(&loc_field.value, exposed_module_ids, module_ids)
})
}
TagUnion { ext, tags } => {
use ast::Tag;
@ -474,14 +553,17 @@ fn contains_unexposed_type(
false
}
Where(loc_ann, _loc_has_clauses) => {
// We assume all the abilities in the `implements` clause are from exported modules.
// TODO don't assume this! Instead, look them up and verify.
contains_unexposed_type(&loc_ann.value, exposed_module_ids, module_ids)
}
As(loc_ann, _spaces, _type_header) => {
contains_unexposed_type(&loc_ann.value, exposed_module_ids, module_ids)
}
SpaceBefore(ann, _) | ast::TypeAnnotation::SpaceAfter(ann, _) => {
contains_unexposed_type(ann, exposed_module_ids, module_ids)
}
@ -572,7 +654,7 @@ fn type_to_docs(in_func_type_ann: bool, type_annotation: ast::TypeAnnotation) ->
.vars
.iter()
.filter_map(|loc_pattern| match loc_pattern.value {
ast::Pattern::Identifier(ident) => Some(ident.to_string()),
ast::Pattern::Identifier { ident, suffixed: _ } => Some(ident.to_string()),
_ => None,
})
.collect(),